在不分层的情况下,一个JDBC事务处理代码片断如下:
try {
conn =DriverManager.getConnection("url","username","userpwd";
conn.setAutoCommit(false);//禁止自动提交,设置回滚点
stmt = conn.createStatement();
stmt.executeUpdate("alter table …"); //数据库更新操作1
stmt.executeUpdate("insert into table …"); //数据库更新操作2
conn.commit(); //事务提交
}catch(Exception ex) {
ex.printStackTrace();
try {
conn.rollback(); //操作不成功则回滚
}catch(Exception e) {
e.printStackTrace();
}
}
对目前的开发来说,基本都会采用分层的架构,如:表现action层、业务逻辑service层、数据访问dao层;
spring对事务做了很好的封装;但是在很多的需求和应用,jdbc还是有其优势的。所以,这里只讨论纯jdbc下分层架构的事务控制。
当采用分层架构的时候,jdbc事务的问题出在:
一 分层架构中,事务控制应该放在哪一层,我的意见:
事务是以业务逻辑为基础的;一个完整的业务应该对应服务层里的一个方法;如果业务操作失败,则整个事务回滚;所以,事务控制是绝对应该放在service层的;
二 如果不同意第一条,认为事务控制可以放在DAO层中,请看下面的例子:
有一个班级业务逻辑类classService,对班级的删除操作,级联到另一张表班级学生关系表的记录删除。
想要将这两个操作放在一个事务中,你可以会这样设计ClassDAO:
public class ClassDAO {
private Connection conn = DBManager.getConnection;
public void delClassAndClassStuReal(String classId) {
try {
conn.setAutoCommit(false);
//班级的删除
//班级学生关系记录的删除
conn.commit(); //事务提交
} catch(SQLException e) {
try {
conn.rollback();
}
}
}
}
但是,DAO层的设计应该遵循一个很重要的原则:DAO层应该保证操作的原子性,就是说DAO里的每个方法都应该是不可以分割的。基于DAO层设计的细粒度原则,classDAO中应该是有这样两个方法:
public class ClassDAO {
public void delClass(String classId) {
//班级的删除
}
public void delClassStuReals(String classId) {
//班级学生关系记录的删除
}
}
那事务的问题就来了:怎样保证这两个删除操作的执行在同一个事务中?
三 如果你原则上同意第一条:
jdbc中事务控制是基于Connection的;虽说事务控制应该放在service层,但是Connection是不应该在service层中被实例出来的。一个有悖解耦的jdbc分层事务控制想法是:
在service层中实例Connection并控制事务;调用dao的时候将这个Connection传给dao层。
这样做,存在明显的耦合:dao层依赖了service层;我们做分层应该是上层依赖下层的,下层依赖上层是不应该出现的。