我有一个jdbc代码,我在代码中使用了事务管理。 以下是代码。我使用的是Mysql数据库。
public class JdbcConn {
public static void main(String[] args){
Savepoint spt1 = null;
Connection con = null;
try{
Class.forName("org.gjt.mm.mysql.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost","root","tany");
con.setAutoCommit(false);
spt1= con.setSavepoint("svpt1");
PreparedStatement psmt;
String query1 = "select city, countryid from querytest.city;";
psmt=con.prepareStatement(query1);
ResultSet rs=psmt.executeQuery();
while(rs.next()){
String query2 = "insert into sun.city (city,countryid) values('"+rs.getString(1)+"',"+rs.getInt(2)+");";
psmt=con.prepareStatement(query2);
psmt.executeUpdate();
}
String query3 = "create database `transtest`;";
psmt=con.prepareStatement(query3);
psmt.executeUpdate();
String query4 = "CREATE TABLE `transtest`.`trans` (`id` tinyint(4) NOT NULL auto_increment,`val` int(5) NOT NULL default 0, PRIMARY KEY (`id`)) ENGINE=MyISAM;";
psmt=con.prepareStatement(query4);
psmt.executeUpdate();
String query5 = "CREATE TABLE `transtest`.`transone` (`id` tinyint(4) NOT NULL auto_increment,`val` int(5) NOT NULL default 0, PRIMARY KEY (`id`)) ENGINE=MyISAM;";
psmt=con.prepareStatement(query5);
psmt.executeUpdate();
String query6 = "CREATE TABLE `transtest`.`transtwo` (`id` tinyint(4) NOT NULL auto_increment,`val` int(5) NOT NULL default 0, PRIMARY KEY (`id`)) ENGINE=MyISAM;";
psmt=con.prepareStatement(query6);
psmt.executeUpdate();
for(int i=1;i<=10;i++){
String query7 = "insert into `transtest`.`transtwo` (`val`) values ("+i*2+");";
psmt=con.prepareStatement(query7);
psmt.executeUpdate();
}
String query8 = "insertd into `transtest`.`trans` (`val`) values (500);";
psmt=con.prepareStatement(query8);
psmt.executeUpdate();
JOptionPane.showMessageDialog(null, "Process completed!");
con.commit();
con.setAutoCommit(true);
}catch(SQLException sqle){
try {
con.rollback(spt1);
JOptionPane.showMessageDialog(null, "Rollback1!");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sqle.getMessage();
sqle.printStackTrace();
}catch (ClassNotFoundException cnfe) {
// TODO Auto-generated catch block
try {
con.rollback(spt1);
JOptionPane.showMessageDialog(null, "Rollback2!");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
cnfe.getMessage();
cnfe.printStackTrace();
}catch (Exception e) {
// TODO Auto-generated catch block
try {
con.rollback(spt1);
JOptionPane.showMessageDialog(null, "Rollback3!");
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.getMessage();
e.printStackTrace();
}
}
}
当sql异常到来时,上面的代码不会回滚。 query1中的表的模式和query2中的表的模式是相同的,但正如您所看到的那样,数据库是不同的。
我只是不知道是否有任何异常,为什么它不会将查询所做的更改从query2回滚到query7。
我在query8中故意在语法上犯了一个语法错误。
请指导我这个问题的朋友,并告诉我知道我的错误代码。
谢谢!
答案 0 :(得分:5)
我将如何做到这一点:
Connection con = null;
boolean ok = false;
try {
con = DriverManager.getConnection(...);
...
con.commit();
ok = true;
} catch (...) {
// diagnose exception
}
...
} finally {
if (con != null) {
try {
if (!ok) con.rollback();
} finally {
con.close();
}
}
}
换句话说,在finally块中进行连接关闭和回滚......并且不要重复代码。
并且DON“T抓住Exception
......见下文。
对该问题的评论说:
作为一般原则,抓住Throwable,而不仅仅是Exception。实际上,只抓住Throwable,不需要重复块。这甚至可以解决你的问题。
捕获Exception
,特别是Throwable
是一个坏主意,除非处理异常后的下一个操作是退出应用程序。可能发生任何数量的潜在未经检查的异常/错误。您无法知道意外异常的原因是什么,或者应用程序是否可以安全地恢复。
但是我的代码中的问题是它没有回滚查询从query2到query7所做的事务
也许是因为其中一些语句是非事务性的(例如CREATE TABLE),并且执行非事务性语句会导致当前事务自动提交。
对于旧版本的MySQL和您正在使用的JDBC驱动程序,可能存在问题。 “org.gjt.mm.mysql”驱动程序真的很老了,我知道早期版本的MySQL根本不支持事务。
正如我所怀疑的那样,你无法回滚MySQL中的CREATE TABLE。
来源:
答案 1 :(得分:2)
您无法在MySQL中回滚create table语句,因为它会导致隐式提交。请参阅:Statements That Cause an Implicit Commit