jforum事务控制是粗粒度控制的,也就是说,对每个请求Service的线程,如果需要获得数据库连接,则
JForumExecutionContext ex = get();
Connection c = ex.conn;
if (validate && c == null) {
c = DBConnection.getImplementation().getConnection();
try {
c.setAutoCommit(!SystemGlobals.getBoolValue(ConfigKeys.DATABASE_USE_TRANSACTIONS));
}
catch (Exception e) {
//catch error autocommit
}
ex.setConnection(c);
set(ex);
}
JForumExecutionContext 是一个执行上下文,持有 connection引用。JForumExecutionContext对每个请求的线程都保存当前 线程的 执行上下文(JForumExecutionContext),每次需要数据库连接时,都从当前线程的本地变量中获得连接,当前线程中的数据库连接为空,就新建一个连接。如果系统配置了需要事务,则:
c.setAutoCommit(!SystemGlobals.getBoolValue(ConfigKeys.DATABASE_USE_TRANSACTIONS));
在此处设置了连接是否 自动提交。
在每次使用完connection,不必关闭连接,而是程序统一在servlet 的Service方法中完成本次请求后释放资源,判断是否提交事务,并且关闭连接。
JForumExecutionContext.finish();
finish实现如下:
public static void finish()
{
Connection conn = JForumExecutionContext.getConnection(false);
if (conn != null) {
if (SystemGlobals.getBoolValue(ConfigKeys.DATABASE_USE_TRANSACTIONS)) {
if (JForumExecutionContext.shouldRollback()) {
try {
conn.rollback();
}
catch (Exception e) {
logger.error("Error while rolling back a transaction", e);
}
}
else {
try {
conn.commit();
}
catch (Exception e) {
logger.error("Error while commiting a transaction", e);
}
}
}
try {
DBConnection.getImplementation().releaseConnection(conn);
}
catch (Exception e) {
logger.error("Error while releasing the connection : " + e, e);
}
}
userData.set(null);
}
这样的实现,事务是控制住了,但是事务的跨度太大,粒度太粗,相反,spring的事务控制 就可以控制到比较细了。
spring声明式事务控制,通过aop,动态代理生成需要控制事务的类,并且注入事务拦截接口而实现的。在spring本地事务中,也是通过ThreadLocal 来持有对当前线程的获得的数据库连接的,使用ThreadLocal好处就是在任何地方都能访问当前线程保存在其中的数据,而不用担心多线程访问的问题,因为每个线程都只能访问当前线程对应的那部分数据。不过对分布式事务的实现而言,ThreadLocal 恐怕帮不上忙了,具体我也不是很清楚,下面请哪位看管讲讲。。。