例如银行转账,涉及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,现在第一次碰到这种问题得请教大家了。

解决方案 »

  1.   

       String sql="update user set money=money-? where name=?;"
            +"update user set money=money+? where name=?;"
            +"update temp set count=count+1 where name=?;";这样试试可以不?
      

  2.   

    jdbc中同时执行多条语句没有弄过,
    不过使用Spring管理事务,在一个事务中执行多条语句应该是可行的吧;
    再次存储过程也是不错的选择的
      

  3.   

    第一种: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语句不灵活,没办法用?号来设置值。用这种方式就好了,因为你的业务是这样的,所以也谈不上什么sql语句不灵活。个人意见
      

  4.   

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

  5.   

    难道大家遇到这种情况都是分开写的吗?
    执行多次ps.executeUpdate()方法吗?
      

  6.   

    是的
    还有,谁说这样效率不好啊,只要你重新获取conn对象,效率是一样的
    jdbc慢在建立连接上
      

  7.   

    可以把一个事务封装到java中,不一定非要把三个语句写到一起,你在java中调用三个更新以后再提交事务就可以了
      

  8.   

    下面经测试可行:                        con.setAutoCommit(false);
    pstat = con.prepareStatement("update userr set money=money-? where name=?");
    pstat.setInt(1, 100);
    pstat.setString(2, "李四");
    pstat.executeUpdate();
    pstat = con.prepareStatement("update userr set money=money+? where name=?");
    pstat.setInt(1, 200);
    pstat.setString(2, "张三");
    pstat.executeUpdate();
    pstat = con.prepareStatement("update temp set count=count+? where name=?");
    pstat.setInt(1, 1);
    pstat.setString(2, "张三");
    pstat.executeUpdate();
    con.commit();
      

  9.   

    PreparedStatement也可以用addBatch,executeBatch啊!
      

  10.   

    这样很好啊,又没有释放链接,只要不重新建立connection就谈不上慢
      

  11.   

    用Spring的事务处理可以做到这一点~
      

  12.   

    三个sql分别执行,然后再统一commit提交事务,这样不行吗?
      

  13.   

    我在很久之前也碰到过这种需求,不记得当时是否解决了。。印象中尝试过下面这种方法,你可以试试看。正在上班手头没有数据库来测试,没法验证
    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();
      

  14.   

    用分号分开语句应该可以的,难道是结束行符号delimiter被修改了?现在没环境测试
    试试看MySQL的连接字符串设置allowMultiQueries参数置为true,如:jdbc:mysql://xxxIp/xxxdb?user=root&password=&allowMultiQueries=true
      

  15.   

    不用sqlserver和mysql,但是你把三条语句分开写然后统一提交回滚跟定没问题的,不用把三条语句非要一次发送到数据库第二绑定变量的问题也是你的写法错了,批量更新的标准做法就是使用绑定变量,不然会产生大量的硬解析,也会占用大量的共享区内存而不适用这些共享的编译语句(ORACLE中式这样)还有你这个程序一般就介绍不可重复读时候的例子,呵呵,注意一下吧,非oracle的数据库在保证一致性和并发性上做的太让人纠结
      

  16.   

    我现在没环境,mysql的驱动是最新版本吗?
    你的sql试试;和下一条update语句空一个空隔看看
      

  17.   

    你错了。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();
      

  18.   

    重新获取conn对象,效率是一样
      

  19.   

    或者分号和下一条update语句之间加入一个换行符看看?
      

  20.   

    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 ";
      

  21.   


    分开执行,这段加上try...catch...,出现异常回滚事务就行了