java批量插入数据库之写绑定变量

最近查到关于sql批量写入和绑定变量的问题,看到了很多好的帖子,再次进行总结


数据库在执行SQL语句时会首先解析SQL语句,解析又分为硬解析与软解析。说到硬解析和软解析,就不能不说一下Oracle对sql的处理过程。当你发出一条sql语句交付Oracle,在执行和获取结果前,Oracle对此sql将进行几个步骤的处理过程:

1、语法检查(syntax check)

  检查此sql的拼写是否语法。

2、语义检查(semantic check)

   诸如检查sql语句中的访问对象是否存在及该用户是否具备相应的权限。

3、对sql语句进行解析(prase)

   利用内部算法对sql进行解析,生成解析树及执行计划。

4、执行sql,返回结果(execute and return)。

其中,软、硬解析就发生在第三个过程里,Oracle利用内部的hash算法来取得该sql的hash值,然后在librarycache里查找是否存在该hash值。假设存在,则将此sql与cache中的进行比较(注意此处的比较哪怕是一个字母的大小写、空格个数不一致都会认为不同)。假设“相同”,就将利用已有的解析树与执行计划,而省略了优化器的相关工作。这也就是软解析的过程;如果上面的2个假设中任有一个不成立,那么优化器都将进行创建解析树、生成执行计划的动作。这个过程就叫硬解析。由此可以看出应该极力避免硬解析,尽量使用软解析。

通过http://blog.csdn.net/duanning397/article/details/7586609 我们看出两者的差距还是很大的


那么如何进行软解析,在这里主要通过绑定变量的方法


      认识绑定变量:

  绑定变量是为了减少解析,比如你有个语句这样的:

  select aaa,bbb from ccc where ddd=eee;

  如果经常通过改变eee这个谓词赋值来查询,如下:

  select aaa,bbb from ccc where ddd=fff;
  select aaa,bbb from ccc where ddd=ggg;
  select aaa,bbb from ccc where ddd=hhh;

  每条语句都要被数据库解析一次,这样比较浪费资源,如果把eee换成绑定变量形式,无论ddd后面是什么值,都不需要重复解析

通过


那么如何在java中实现绑定变量,主要用两种方法,一种是?号法,比较简单粗暴,适合大部分情况

具体可以参考http://blog.csdn.net/wacthamu/article/details/7798393 这里转载一些关键内容

 Java实现绑定变量的方法:

PreparedStatement pstmt = con.prepareStatement("UPDATE employees SET salay = ? WHERE id = ?");
pstmt.setBigDecimal(1, 15.00);
pstmt.setInt(2, 110592);
//result statmement:   UPDATE employees SET salay = 15.00 WHERE id =110592
pstmt.executeQuery();

  假设要将id从1到10000的员工的工资都更新为150.00元,不使用绑定变量,则:

sql.executeQuery("UPDATE employees SET salay = 150.00 WHERE id = 1");
sql.executeQuery("UPDATE employees SET salay = 150.00 WHERE id = 2");
sql.executeQuery("UPDATE employees SET salay = 150.00 WHERE id = 3");
sql.executeQuery("UPDATE employees SET salay = 150.00 WHERE id = 4");
....
sql.executeQuery("UPDATE employees SET salay = 150.00 WHERE id = 10000");

  使用绑定变量,则:

PreparedStatement pstmt;
for (id = 1; id < 10000; id++)
{
   if (null == pstmt)
     pstmt = con.prepareStatement("UPDATE employees SET salay = ? WHERE id = ?");
   pstmt.setBigDecimal(1, 150.00);
   pstmt.setInt(2, id);
   pstmt.executeQuery();
}
       需要注意的是pstmt.executeQuery();是每次都打开游标,所以出国处理大数据的话,则需要在后面添加pstmt.close();

  这里可以看到通过设置的方式可以让数据库认为成一条语句,这里必须按照这种方法,如果用简单的字符串拼接的方法,数据库依然认为成两条语句具体可以参考http://www.itpub.net/thread-263389-1-1.html


那么第二种方法是什么呢,细心的网友可以看到http://blog.csdn.net/wacthamu/article/details/7798393 已经提及,即使用:x的方式,其中该文章,也给出了一样的赋值方式,

其实Oracle遵循针对PL/SQL存储过程使用占位符名称匹配的原则,而针对SQL语句则采用占位符位置匹配的原则。所以上文的:x更多的是在Oracle中的本身里面,对比两者可以发现,一种是单纯的问号,一种是用变量名,当赋值的变量是重复的时候,用后者可以避免重复书写,但后者由于是变量名,也会导致书写错误,

在近期研究中发现,在hibernate中的hql语言其实也是可以占位符名称匹配,这里给出一个完整的hql的存储例子

<span style="color:#333333;">StringBuffer hql = new StringBuffer();
        hql.append("select distinct employee  from PreceptPO pre,PlanPO plan, ").append(
                "EmployeeInfoPO employee,ObjectRelationPO relation ");
        hql.append(" where pre.oid=plan.preceptID");
        hql.append(" and pre.status='").append(PreceptStatusType.STARTUP.getCode()).append("'");
        hql.append(" and plan.objectID=employee.oid ");
        hql.append(" and relation.relationObjectID=:employeeID ");
        hql.append(" and relation.preceptID=plan.preceptID ");
        hql.append(" and relation.objectID=plan.objectID ");
        hql.append(" and relation.phase=plan.phase ");
        hql.append(" and (relation.performanceRole=3 or relation.performanceRole=4 )");
        

        //员工状态
        hql.append(" and ");
        DAOHelper.buildOrHql(hql, "employee.employeeStatus",
                StaffStatusAttribute.Normal_Employee.getStatus());

        Query q = getSession().createQuery(hql.toString());
        /*if(empList.size() > 0){
        	</span><span style="color:#ff0000;"><strong>q.setParameterList("empList", empList);	</strong></span><span style="color:#333333;">
        }*/
        
        q.setLong("employeeID", appraiserID);</strong>
        objectList = q.list();
        
        List voList = new ArrayList(objectList.size());
        for (Iterator iter = objectList.iterator(); iter.hasNext();) {
            EmployeeInfoPO emp = (EmployeeInfoPO) iter.next();
            voList.add(EmployeeBasicConvert.convert(emp));
        }
    	return voList;
	}</span>

这个时候很多人会说,既然使用了createQuery,那使用createSQLQuery可不可以用占位符名称匹配,答案是可以的,下面给出了例子

StringBuffer buffer = new StringBuffer();
/*
		buffer.append(" select count(1) as num from TB_PMG_OBJECTRELATION orn,TB_PMG_PLAN pl ")
		      .append(" left join TB_PMG_EVALUATESCORE on TB_PMG_EVALUATESCORE.c_planid = pl.c_oid_plan ")
	          .append(" and TB_PMG_EVALUATESCORE.c_status in (2,3,5,7) ")
	          .append(" where pl.c_oid_plan=").append(planID)
	          .append(" and pl.c_objectid = orn.c_objectid ")
	          .append(" and orn.c_preceptid = pl.c_preceptid and orn.c_phase = pl.c_phase ")
	          .append(" and orn.c_level = '2' and orn.c_businessrole='1' ")
	          .append("  and TB_PMG_EVALUATESCORE.C_OID_EVALUATESCORE is not null");
*/
		buffer.append(" SELECT COUNT(1) AS NUM FROM TB_PMG_OBJECTRELATION ORN  ")
	      .append(" LEFT JOIN  TB_PMG_EVALUATESCORE e on e.C_STATUS IN (2,3,5,7)")
	      .append(" AND ORN.C_PRECEPTID = e.c_preceptID ")
	      .append(" AND ORN.C_PHASE = e.c_phase ")
	      .append(" AND ORN.C_objectID = e.c_objectID ")
	      .append(" WHERE  ")
	      .append(" ORN.C_OBJECTID =:objectID  ")
	      .append(" AND ORN.C_PRECEPTID = :preceptID AND ORN.C_PHASE = :phase ")
	      .append(" AND ORN.C_LEVEL = '2' AND ORN.C_BUSINESSROLE='1' ")
	      .append(" AND e.C_OID_EVALUATESCORE IS NOT NULL ");

		SQLQuery q= loadSession().createSQLQuery(buffer.toString());
		q.setParameter("preceptID", preceptID);
		q.setParameter("phase", phase);
		q.setParameter("objectID", objectID);</strong>
		q.addScalar("num", Hibernate.LONG);
		List list = q.list();



其实在大型工程中,占位符名称匹配用的很多,但如果就是用单纯的sql语句怎么实现呢?,下文给出了方式http://blog.csdn.net/keyboardsun/article/details/4275594

这里需要用一个自定义函数,进行拼接赋值,这里面还对不用类型的内容进行转换,比如时间,数字等比较复杂的转换,所以这个自定义函数可以作为一个工具类


很感谢以上所有的博主,给我的帮助,在这里也专程感谢


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Oracle 数据库中,可以使用绑定变量进行多行插入操作。以下是一个示例: 假设我们有一个名为 `employees` 的表,它有三个列:`id`、`name` 和 `salary`。现在我们要插入多行数据到这个表中。 首先,我们需要准备一个包含要插入的数据的列表。例如,我们准备了以下数据: ``` [ (1, 'John', 5000), (2, 'Jane', 6000), (3, 'Mike', 7000) ] ``` 然后,我们可以使用 INSERT INTO 语句结合绑定变量来实现多行插入。下面是示例代码: ```sql -- 准备要插入的数据列表 DECLARE TYPE employee_list IS TABLE OF employees%ROWTYPE; employees_data employee_list := employee_list( (1, 'John', 5000), (2, 'Jane', 6000), (3, 'Mike', 7000) ); BEGIN -- 使用 FORALL 语句进行多行插入 FORALL i IN employees_data.FIRST..employees_data.LAST INSERT INTO employees (id, name, salary) VALUES (employees_data(i).id, employees_data(i).name, employees_data(i).salary); COMMIT; END; ``` 在上面的示例代码中,我们首先声明了一个自定义类型 `employee_list`,它是 `employees` 表的行类型的集合。然后,我们初始化一个名为 `employees_data` 的变量,该变量包含要插入的数据。 接下来,我们使用 `FORALL` 语句结合 `INSERT INTO` 语句进行多行插入。`FORALL` 语句是用于批量处理的特殊语句,可以显著提高插入性能。在循环中,我们通过索引 `i` 来访问 `employees_data` 列表中的每一行数据,并将其插入到 `employees` 表中。 最后,我们使用 `COMMIT` 语句提交事务,将更改保存到数据库中。 这样,我们就可以使用绑定变量实现 Oracle 数据库的多行插入操作了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值