精华内容
下载资源
问答
  • 2021-01-25 18:31:13

    根据自己有限的java数据库编程的经验,对sql做预处理可以提高执行的效率,所以对mysql的c API做了些探索。从好坏两方面来总结mysql提供的这些接口:

    好处是,他提供的是一种buffer的机制,我对它做了优化,就是为所有的参数buffer数据创建了一个大的静态的或者全局缓冲区,这样每次改变buffer内容的时候只需要对相应的字段赋值即可,不需要每次重新设置buffer指向的内存,因为这块内存是不变的,参数字段名字和这个内存地址做一个map,赋值的时候可以直接查找到参数的地址。如果有多个prepare statement,且是一个线程内,这块数据缓存可以共同利用,互不干扰的。如果用的hash_map,效率很高,每次参数赋值的消耗是很少的,几乎等同于变量赋值的。

    需要注意的是sql字段类型,buffer_type枚举,c ++数据类型之间的映射关系,必须保证不会内存越界。buffer_length可以不指定的,那样就会直接使用length了,当然这是update/insert,如果是select还是要有的。读了mysql的driver的源码才确定了在bind param的时候是如何赋值内存的,如果不是blob 或者buffer长度。在调试时,如果发现写到数据库的和程序中的值不一致,这是可能的问题根源。

    我不确定prepare statement在执行时究竟是走的拼sql的流程还是有一个专门的二进制协议来只传递参数值,源代码中这段没找到。我测出来的是执行prepare statement和直接执行sql语句的效率基本上是一致的,有很小很小的提高。

    因此,我确定,使用prepare statement的最大节省的是拼sql语句的消耗,如果拼的话往往要使用字符串流的机制,效率比较低,这部分的时间消耗等于执行sql的消耗。理想的情况,不适用prepare statement,弄一个sql语句,拼的时候在参数的地方预留缓冲区,然后赋值的时候就直接把值放到缓冲里,然后把sql直接执行就好了,难题在于变长的char*和blob的缓冲区如何分配,分配的一个足够大的缓冲,如果实际值不够长的话就填充空格。这个还在瞎想阶段,实现起来很难。

    使用了prepare statement也省去了escape特殊字符的麻烦,提高了安全性。

    问题在于我对一个prepare statement的各个参数每次用到的可能不同,这次用这个参数,不用另一个参数,这样prepare statement就不同了,只好重新建一个。如果有十几个字段,每次不确定用哪几个字段,这在只修改需要修改的内容时是必须的,为了减少不必要的存档生成,当然这个情景很特殊。。。却是我所面对的。如果能在param的buffer增加一个字段来表示这个字段是否有效就好了,可惜没有。

    prepare statement需要长期占用数据库连接,这个对于有限的连接数也是一个问题,又、需要有一个类似于连接池的prepare statement池机制啊。。。

    这就是我的总结了,具体代码网上搜一大堆。读了源代码收获比较大,它能让我完全确认它是如何工作的。

    Great open source!

    阅读(5292) | 评论(0) | 转发(0) |

    更多相关内容
  • 我们可以把sql预处理看作是想要运行的 SQL 的一种编译过的模板,它可以使用变量参数进行定制。 我们来看下它有什么好处: 预处理语句大大减少了分析时间,只做了一次查询(虽然语句多次执行)。 绑定参数减少了...
  • 1. 使用场景:批量执行sql语句,可以提高查询速度 package main import ( "database/sql" "fmt" _ "github.com/go-sql-driver/mysql" "time" ) var db *sql.DB func initMySQL()(err error){ dsn := "root:root...

    1. SQL预处理的使用

    使用场景:批量执行sql语句,可以提高查询速度

    为什么要预处理 ?

    1)优化MySQL服务器重复执行SQL的方法,可以提升服务器性能,提前让服务器编译,一次编译多次执行,节省后续编译的成本

    2)避免SQL注入问题

    package main
    import (
    "database/sql"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "time"
    )
    var db *sql.DB
    
    func initMySQL()(err error){
    	dsn := "root:root@tcp(127.0.0.1:13306)/go_test"
    	//去初始化全局的db对象,而不是新声明一个变量
    	db,err = sql.Open("mysql",dsn)
    	if err != nil {
    		panic(err)
    	}
    	//做完错误检查后,确保db不为nil
    
    	//尝试与数据库建立连接(校验dsn是否正确)
    	err = db.Ping()
    	if err != nil {
    		fmt.Printf("connect to db failed,err: %v\n",err)
    		return err
    	}
    	//根据实际业务设置数值
    	db.SetConnMaxLifetime(time.Second*10) // 设置连接可以重复使用的最长时间
    	db.SetMaxOpenConns(500) // 最大连接数
    	db.SetMaxIdleConns(200) // 最大空闲连接数
    	return
    }
    type user struct {
    	id int
    	age int
    	name string
    }
    
    //预处理查询示例
    func prepareQueryDemo() {
    	// Prepare创建一个准备好的用于之后的查询和命令。返回值可以同时执行多个查询和命令
    	sqlStr := "SELECT id,name,age FROM user WHERE id>?"
    	stmt, err := db.Prepare(sqlStr)
    	if err != nil {
    		fmt.Printf("prepare failed, err:%v\n",err)
    		return
    	}
    	defer stmt.Close()
    	rows, err := stmt.Query(0)
    	if err != nil {
    		fmt.Printf("query failed, err:%v\n",err)
    		return
    	}
    	defer rows.Close()
    	// 循环读取结果集中的数据
    	for rows.Next() {
    		var u user
    		//需要调用Scan去释放数据库链接
    		err := rows.Scan(&u.id,&u.name,&u.age)
    		if err != nil {
    			fmt.Printf("scan failed,err:%v\n",err)
    			return
    		}
    		fmt.Printf("id:%d,name:%s,age:%d\n",u.id,u.name,u.age)
    	}
    }
    func main() {
    	if err := initMySQL();err != nil {
    		fmt.Printf("connect to db failed,err:%v\n",err)
    	} else {
    		fmt.Println("db connect to db success")
    	}
    	// Close() 用来释放数据库连接的相关资源
    	defer db.Close()
    	prepareQueryDemo()
    }

    2.SQL注入问题

    注意:我们任何时候都不应该自己拼接SQL语句

    #符号为注释符,忽略后面的sql语句,#为mysql特有的注释符

    应该用 -- 

    package main
    import (
    	"database/sql"
    	"fmt"
    	_ "github.com/go-sql-driver/mysql"
    	"time"
    )
    var db *sql.DB
    
    func initMySQL()(err error){
    	dsn := "root:root@tcp(127.0.0.1:13306)/go_test"
    	//去初始化全局的db对象,而不是新声明一个变量
    	db,err = sql.Open("mysql",dsn)
    	if err != nil {
    		panic(err)
    	}
    	//做完错误检查后,确保db不为nil
    
    	//尝试与数据库建立连接(校验dsn是否正确)
    	err = db.Ping()
    	if err != nil {
    		fmt.Printf("connect to db failed,err: %v\n",err)
    		return err
    	}
    	//根据实际业务设置数值
    	db.SetConnMaxLifetime(time.Second*10) // 设置连接可以重复使用的最长时间
    	db.SetMaxOpenConns(500) // 最大连接数
    	db.SetMaxIdleConns(200) // 最大空闲连接数
    	return
    }
    type user struct {
    	id int
    	age int
    	name string
    }
    // sql注入示例
    func sqlInjectDemo(name string) {
    	sqlStr := fmt.Sprintf("select id, name, age from user where name='%s'", name)
    	fmt.Printf("SQL:%s\n", sqlStr)
    	var u user
    	err := db.QueryRow(sqlStr).Scan(&u.id, &u.name, &u.age)
    	if err != nil {
    		fmt.Printf("exec failed, err:%v\n", err)
    		return
    	}
    	fmt.Printf("user:%#v\n", u)
    }
    func main() {
    	if err := initMySQL();err != nil {
    		fmt.Printf("connect to db failed,err:%v\n",err)
    	} else {
    		fmt.Println("db connect to db success")
    	}
    	// Close() 用来释放数据库连接的相关资源
    	defer db.Close()
    	sqlInjectDemo("xxxx' or 1=2#")
    }

    展开全文
  • Java sql 预处理的封装

    2021-02-12 20:43:28
    除了select其他的基本都和insert一致. 因为select得到的结果集需要在处理完结果集后关闭数据库的连接.所以用到监听回调的...DBUtils.select(sql, new DBUtils.Listener() {@Overridepublic void callback(ResultS...

    除了select其他的基本都和insert一致. 因为select得到的结果集需要在处理完结果集后关闭数据库的连接.所以用到监听回调的办法.

    String sql = "select * from comment where fid=?";

    DBUtils.select(sql, new DBUtils.Listener() {

    @Override

    public void callback(ResultSet resultSet) {

    try {

    while(resultSet.next()){

    System.out.println(resultSet.getInt(1));

    System.out.println(resultSet.getString(5));

    }

    } catch (SQLException e) {

    e.printStackTrace();

    }

    }

    },1);

    我试想的是我在实际场景中可能会用到如下两种插入的操作:

    // 第一种

    String sql = "insert into comment (fid,uid,cont) values (?,?,?)";

    DBUtils.insert(sql,100,50,"才是真的好");

    // 第二种

    DBUtils.insert("insert into comment (fid,uid,cont) values (1,2,'广州好迪')");

    /**

    * 预处理参数设置

    * @param statement

    * @param params

    * @return

    * @throws SQLException

    */

    private static PreparedStatement paramsSet(PreparedStatement statement, Object... params) throws SQLException {

    int paramSize = params.length;

    for(int i=1; i<=paramSize; i++){

    Object param = params[i-1];

    if(param instanceof java.lang.Integer){

    statement.setInt(i,(Integer)param);

    }else if(param instanceof java.lang.String){

    statement.setString(i, (String) param);

    }else if(param instanceof java.lang.Float){

    statement.setFloat(i, (Float) param);

    }else if(param instanceof java.lang.Long){

    statement.setLong(i,(Long)param);

    }else if(param instanceof java.lang.Double){

    statement.setDouble(i,(Double)param);

    }else if(param instanceof java.sql.Date){

    statement.setDate(i, (Date)param);

    }else{

    statement.setObject(i,param);

    }

    }

    return statement;

    }

    /**

    * 插入操作

    * @param sql

    * @param params

    * @return

    */

    public static int insert(String sql, Object... params){

    int paramSize = sql.length() - sql.replaceAll("\\?","").length();

    int paramsNum = params.length;

    if (paramSize != paramsNum) {

    return -1;

    }

    if (!sql.toLowerCase().startsWith("insert")) {

    return -1;

    }

    Connection conn = null;

    PreparedStatement statement = null;

    try {

    conn = getConnection();

    statement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);

    if(paramSize > 0){

    statement = paramsSet(statement,params);

    }

    statement.executeUpdate();

    ResultSet rs = statement.getGeneratedKeys();

    if (rs.next()){

    return rs.getInt(1);

    }

    }catch (SQLException e){

    e.printStackTrace();

    }finally {

    closeConnection(statement, conn);

    }

    return 0;

    }

    public static int insert(String sql,ArrayList data){

    return insert(sql, data.toArray());

    }

    测试了下,插入 OK. 棒棒的,没错又是好友@明明帮忙,参数Object...表示任意多个参数,这点非常不错.我们在 php 里面与之类似的就是func_get_args和func_num_args.

    展开全文
  • 主要介绍了java使用JDBC动态创建数据表及SQL预处理的方法,涉及JDBC操作数据库的连接、创建表、添加数据、查询等相关实现技巧,需要的朋友可以参考下
  • mysql的SQL预处理

    2019-10-11 16:49:18
    我们一般处理SQL语句时,都是即时的,mysql客户端发送一条SQL语句到mysql服务器,mysql... 对于这一问题我们通过SQL预处理,可以很好地解决这一问题。SQL预处理步骤一般为prepare,execute,drop。 我们现在来...

      我们一般处理SQL语句时,都是即时的,mysql客户端发送一条SQL语句到mysql服务器,mysql服务器进行编译处理运行。但是有的时候我们会重复的执行一条SQL语句,这是使用即时处理,就会造成很大的资源浪费,而且耗费时间,特别是操作大量数据时。

      对于这一问题我们通过SQL预处理,可以很好地解决这一问题。SQL预处理步骤一般为prepare,execute,drop。

      我们现在来测试一下SQL预处理。

      先连接数据库。

      先预处理SQL。

      在执行预处理SQL,注意占位符要按照顺序来。

      我们可以查找到数据,然后在删除预处理SQL。

      这就是SQL预处理的一般过程。

      预编译语句的优势在于归纳为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止 SQL 注入。

     

      

    展开全文
  • PrepareStatement(sql预处理类)import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import javax.swing....
  • 先把命令部分发送给MySQL服务端,MySQL服务端进行SQL预处理。 然后把数据部分发送给MySQL服务端,MySQL服务端对SQL语句进行占位符替换。 MySQL服务端执行完整的SQL语句并将结果返回给客户端。 为什么要预处理? 优化...
  • mysql中的sql预处理

    2017-09-28 10:08:27
    所谓的预处理技术,最初也是由MySQL提出的一种减轻服务器压力的一种技术! 传统mysql处理流程 1, 在客户端准备sql语句 2, 发送sql语句到MySQL服务器 3, 在MySQL服务器执行该sql语句 4, 服务器...
  • SQL语句预处理

    2021-02-28 09:17:13
    执行预处理SQL语句 a、描述:执行一条预处理语句 b、语法:bool PDOStatement::execute( ) c、返回:成功时返回 TRUE, 或者在失败时返回 FALSE。 ":value"占位符综合示例: //$dsn,数据源名称或叫做 DSN,包含...
  • PHP SQL预处理

    2019-10-04 22:30:17
    php预处理查询 $query='insert into p1(info) values(?)'; $query2='select info from p1 where id=?...// 创建预处理语句 $stmt=mysqli_stmt_init($link); if (mysqli_stmt_prepare($stmt,$query2...
  • Prepared SQL Statement:SQL的执行、预编译处理语法、注意点一、SQL 语句的执行处理1、即时 SQL一条 SQL 在 DB 接收到最终执行完毕返回,大致的过程如下:1. 词法和语义解析;2. 优化 SQL 语句,制定执行计划;3. ...
  • 预处理SQL语句

    千次阅读 2020-08-19 13:36:37
    所谓预处理指的就是将SQL语句中的关键字(如 SELECT…FROM…)与数据(如字段名,数据表名)分离,使得针对不同数据的相同SQL语句的执行开销更小,同时又可防止SQL注入的攻击 **传统方式的SQL语句,**在执行时每条SQL都...
  • MySQL预处理动态拼接的sql语句 背景:将sqlserver存储过程翻译到mysql中 需求:执行动态拼接的sql语句,并获取其语句的输出结果 问题: sqlserver中使用了如下代码执行动态拼接语句,并获取输出结果 EXEC sp_execute...
  • 许多成熟的数据库都支持预处理语句(Prepared Statements)的概念。它们是什么东西?你可以把它们想成是一种编译过的...概述预处理语句用于执行多个相同的 SQL 语句,并且执行效率更高。预处理语句的工作原理如下:预...
  • 2019独角兽企业重金招聘Python工程师标准>>> 许多成熟的数据库都支持预处理语句(Prepared Statements)的...SQL预处理语句 转载于:https://my.oschina.net/u/616147/blog/1793442
  • worm支持SQL语句的预编译,使用SQL语句预编译可以提升数据库访问的效率。在worm中可以通过三种方式开启SQL语句预编译:全局开启、会话中开启、语句中开启。
  • MySQL快查 因为在日常工作学习中经常忘记mysql的...预处理SQL语句MySQL快查创建预处理语句执行预处理语句释放预处理语句 MySQL数据库中的prepare、execute、deallocate统称为预处理语句。 创建预处理语句 prepare stmt
  • 想执行的语句是select id,uid,fnum,cont,icons,ts from feed where id in... } 从查询的结果来看,实际执行的 sql 是select id,uid,fnum,cont,icons,ts from feed where id in (1) 最后我的解决办法就是直接组装这条 SQL
  • PHP防止sql注入小技巧之sql预处理

    千次阅读 2018-08-29 09:58:01
    我们可以把sql预处理看作是想要运行的 SQL 的一种编译过的模板,它可以使用变量参数进行定制。 我们来看下它有什么好处: 预处理语句大大减少了分析时间,只做了一次查询(虽然语句多次执行)。 绑定参数...
  • SQL预处理语句(Prepared Statements)

    万次阅读 2012-05-20 11:03:07
    SQL预处理语句(Prepared Statements) 许多成熟的数据库都支持预处理语句(Prepared Statements)的概念。它们是什么东西?你可以把它们想成是一种编译过的要执行的SQL语句模板,可以使用不同的变量参数定制它。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 55,271
精华内容 22,108
关键字:

sql预处理

友情链接: recoro.zip