jdbc中同时执行多条sql语句的问题。

qunhao 2011-05-31 02:10:11
例如银行转账,涉及3条sql语句,其中一条是记录张三的转账次数,这就需要3条sql语句一起执行,才好做事务。
update user set money=money-100 where name='张三'
update user set money=money+100 where name='李四'
update temp set count=count+1 where name='张三'

之前我都是用SQLServere2005的,我的做法是如下:

Connection conn = DBUtilc3p0.getInstance().getConnection();
PreparedStatement ps = null;
try {
conn.setAutoCommit(false);
String sql="update user set money=money-? where name=? "
+"update user set money=money+? where name=? "
+"update temp set count=count+1 where name=? ";
ps = conn.prepareStatement(sql);
ps.setInt(1, 100);
ps.setString(2, "张三");
ps.setInt(3, 100);
ps.setString(4, "李四");
ps.setString(5, "张三");
ps.executeUpdate();
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
closeAll(conn, ps, null);
}


以上代码执行正常,没有问题。我一直以来都是这么干的。

我的问题是,我现在换成MySQL数据库,我发现MySQL的jdbc驱动不支持我上面这种写法,我把sql语句改成如下,语句间用;号隔开,还是不行,会报错。看来MySQL不允许一次执行多条sql语句。
String sql="update user set money=money-? where name=?;"
+"update user set money=money+? where name=?;"
+"update temp set count=count+1 where name=?;";

我查了下,MySQL可能得用批处理才行,但是我发现用批处理的话我所知道的有如下两种方式,但都不合适我的需求
第一种:

Statement ps=conn.createStatement();
ps.addBatch("update user set money=money-100 where name='张三'");
ps.addBatch("update user set money=money+100 where name='李四'");
ps.addBatch("update temp set count=count+1 where name='张三'");
ps.executeBatch();

这个方式可行,但是可以发现,我用的是Statement,所以我的sql语句不灵活,没办法用?号来设置值。

第二种:

PreparedStatement ps=conn.prepareStatement("insert into temp values(?)");
ps.setInt(1, 100);
ps.addBatch();
ps.setInt(1, 200);
ps.addBatch();
ps.executeBatch();

这个可以用?号来设置值,但是只能是同一条sql语句去设置不同的值,我的需求还有一条记录张三的转账次数的sql语句。

mysql驱动是最新的。
到现在为止我还是找不到方法可以满足的我上面的需求,用SQLServer2005就没有这样的问题了,没办法,项目需要换MySQL,现在第一次碰到这种问题得请教大家了。
...全文
18204 40 打赏 收藏 转发到动态 举报
写回复
用AI写文章
40 条回复
切换为时间正序
请发表友善的回复…
发表回复
菜继续 2011-06-02
  • 打赏
  • 举报
回复
重新获取conn对象,效率是一样
zhouYunan2010 2011-06-02
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 afer198215 的回复:]
引用 20 楼 hudie1234567 的回复:
PreparedStatement也可以用addBatch,executeBatch啊!

UP
[/Quote]
你错了。addBatch只可以对同一条sql语句进行批量操作。比如批量删除一条记录。
举一个例子:

String sql = delete from annex where annexcode = ?;
String[] codes = {'aa','bb','cc'}
pst = cn.prepareStatement(sql);
for(int i=0;i<codes.length;i++){
pst.setString(1, codes[i]);
pst.addBatch();
}
pst.excuteBatch();
eclipse_xu 2011-06-02
  • 打赏
  • 举报
回复
存储过程 是个不错的选择
小绵羊 2011-06-02
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 afer198215 的回复:]

引用 20 楼 hudie1234567 的回复:
PreparedStatement也可以用addBatch,executeBatch啊!

UP
[/Quote]
up
UPC_思念 2011-06-02
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 zhouyunan2010 的回复:]

不要写在一起,分开执行可以吗?比如用一个con获取3个prepareStatement对象。
conn.setAutoCommit(false);
pst = con.prepareStatement(sql1);
pst.set......;
pst.executeUpdate();
pst = con.prepareStatement(sql2);
pst.set......;
……
[/Quote]

分开执行,这段加上try...catch...,出现异常回滚事务就行了
qybao 2011-06-02
  • 打赏
  • 举报
回复
have try
String sql="update user set money=money-? where name=? ;\n "
+"update user set money=money+? where name=? ;\n "
+"update temp set count=count+1 where name=? ;\n ";
qybao 2011-06-02
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 qybao 的回复:]
引用 32 楼 qunhao 的回复:
引用 30 楼 qybao 的回复:
用分号分开语句应该可以的,难道是结束行符号delimiter被修改了?现在没环境测试
试试看MySQL的连接字符串设置allowMultiQueries参数置为true,如:jdbc:mysql://xxxIp/xxxdb?user=root&amp;amp;password=&amp;amp;al……
[/Quote]
或者分号和下一条update语句之间加入一个换行符看看?
茫茫大海 2011-06-01
  • 打赏
  • 举报
回复
[Quote=引用楼主 qunhao 的回复:]
我查了下,MySQL可能得用批处理才行,但是我发现用批处理的话我所知道的有如下两种方式,但都不合适我的需求
第一种:
Java code
Statement ps=conn.createStatement();
ps.addBatch("update user set money=money-100 where name='张三'");
ps.addBatch("update user set money=money+100 where name='李四'");
ps.addBatch("update temp set count=count+1 where name='张三'");
ps.executeBatch();
这个方式可行,但是可以发现,我用的是Statement,所以我的sql语句不灵活,没办法用?号来设置值。
[/Quote]
PreparedStatement也可以用addBatch,executeBatch啊!
exterminator 2011-06-01
  • 打赏
  • 举报
回复
我在很久之前也碰到过这种需求,不记得当时是否解决了。。印象中尝试过下面这种方法,你可以试试看。正在上班手头没有数据库来测试,没法验证。。。
PreparedStatement ps=conn.prepareStatement("update user set money = money-100 where name = ?");
ps.setString(1, "张三");
ps.addBatch();
ps=conn.prepareStatement("update user set money = money+100 where name = ?");
ps.setString(1, "李四");
ps.addBatch();
ps=conn.prepareStatement("update temp set count = count + 1 where name = ?");
ps.setString(1, "张三");
ps.addBatch();
ps.executeBatch();
brightyq 2011-06-01
  • 打赏
  • 举报
回复
三个sql分别执行,然后再统一commit提交事务,这样不行吗?
wj539h 2011-06-01
  • 打赏
  • 举报
回复
你弄个循环不就OK了,比如说执行10个一提交
想喝咖啡的貓 2011-06-01
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 hudie1234567 的回复:]
PreparedStatement也可以用addBatch,executeBatch啊!
[/Quote]
UP
uastation 2011-06-01
  • 打赏
  • 举报
回复
用Spring的事务处理可以做到这一点~
oklinsong 2011-06-01
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 bennyraul 的回复:]

可以把一个事务封装到java中,不一定非要把三个语句写到一起,你在java中调用三个更新以后再提交事务就可以了
[/Quote]
这样很好啊,又没有释放链接,只要不重新建立connection就谈不上慢
Jeelon 2011-06-01
  • 打赏
  • 举报
回复
干嘛用存储过程 你这样效率也不高啊...
qybao 2011-06-01
  • 打赏
  • 举报
回复
[Quote=引用 32 楼 qunhao 的回复:]
引用 30 楼 qybao 的回复:
用分号分开语句应该可以的,难道是结束行符号delimiter被修改了?现在没环境测试
试试看MySQL的连接字符串设置allowMultiQueries参数置为true,如:jdbc:mysql://xxxIp/xxxdb?user=root&amp;password=&amp;allowMultiQueries=true


刚试了……
[/Quote]
我现在没环境,mysql的驱动是最新版本吗?
你的sql试试;和下一条update语句空一个空隔看看
qunhao 2011-06-01
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 qybao 的回复:]
用分号分开语句应该可以的,难道是结束行符号delimiter被修改了?现在没环境测试
试试看MySQL的连接字符串设置allowMultiQueries参数置为true,如:jdbc:mysql://xxxIp/xxxdb?user=root&password=&allowMultiQueries=true
[/Quote]

刚试了这个,还是不可以。
loveofmylife 2011-06-01
  • 打赏
  • 举报
回复
不用sqlserver和mysql,但是你把三条语句分开写然后统一提交回滚跟定没问题的,不用把三条语句非要一次发送到数据库

第二绑定变量的问题也是你的写法错了,批量更新的标准做法就是使用绑定变量,不然会产生大量的硬解析,也会占用大量的共享区内存而不适用这些共享的编译语句(ORACLE中式这样)

还有你这个程序一般就介绍不可重复读时候的例子,呵呵,注意一下吧,非oracle的数据库在保证一致性和并发性上做的太让人纠结
qybao 2011-06-01
  • 打赏
  • 举报
回复
用分号分开语句应该可以的,难道是结束行符号delimiter被修改了?现在没环境测试
试试看MySQL的连接字符串设置allowMultiQueries参数置为true,如:jdbc:mysql://xxxIp/xxxdb?user=root&password=&allowMultiQueries=true

kangkai_it 2011-06-01
  • 打赏
  • 举报
回复
\'\'\'
加载更多回复(19)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧