当我们读数据库进行操作的时候,有些时候“事物的管理”是避免不了的。从事物的开启,提交、回滚的基本操作来说,还有包括在这些操作之间的逻辑代码,我们必须保证这些链接数据库对象的Connection是同一个。只有这样我们才能保证事物的完整性。还有,当我们管理事物时,我们需要将管理事物的操作封装成一个动态代理类,这样一来,我们可以很容易将事物的管理嵌套在业务逻辑中。
1、保证数据库链接对象一致的问题:我们可以用ThreadLocal对象存放当前线程的Connection对象,这样不但保证了其它线程读取不到此线程内的Connection对象,当我们获取Connection对象时,还能保证是同一个。下面是具体的代码。
public class TransationManager {
private static ThreadLocal<Connection> t1 = new ThreadLocal<Connection>();
public static Connection getConnection() {
Connection conn = t1.get();
if (conn == null) {
conn = DBCPUtil.getConnection();
t1.set(conn);// 将连接绑在当前线程上
}
return conn;
}
// 开启事物
public static void startTransaction() {
Connection conn = getConnection();
try {
conn.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
// 提交事物
public static void commit() {
Connection conn = getConnection();
try {
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 回滚事物
public static void rollback() {
Connection conn = getConnection();
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 释放资源
public static void release() {
Connection conn = getConnection();
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
2、利用动态代理封装一个BeanFactory,当我们需要管理事物时,就生成代理对象,让代理对象帮我们实现,这里还体现了面向切面编程的思想(AOP),当我们不需要事物的一些操作时,我们可以生成具体的业务逻辑对象。代码如下。
public class BeanFactory {
public static BusinessService getBusinessService(boolean isProxy) {
final BusinessService s = new BusinessServiceImpl();
if (isProxy) {
// 返回代理实现类
BusinessService proxyS = (BusinessService) Proxy.newProxyInstance(s
.getClass().getClassLoader(), s.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
Object rtValue = null;
try {
TransationManager.startTransaction();// 开启事物
rtValue = method.invoke(s, args); // 此处是我的代理的方法
TransationManager.commit(); // 提交事物
} catch (Exception e) {
TransationManager.rollback(); // 回滚事物
throw new RuntimeException(e);
} finally {
TransationManager.release(); // 释放资源
}
return rtValue;
}
});
return proxyS;
} else {
return s;
}
}
}
3、当我们用commons-dbutils-1.4.jar包管理我们的JDBC操作时,我们不要忘了往QueryRunner对象的CRUD方法中传入Connection对象。这里小编用D层的一段查询和更新代码举例。
public class AccountDaoImpl implements AccountDao {
private QueryRunner qr = new QueryRunner();
// 查询操作
public Account findAccountByName(String accountName) {
try {
return qr.query(TransationManager.getConnection(),
"select * from account where name=?",
new BeanHandler<Account>(Account.class), accountName);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
// 更新操作
public void updateAccount(Account account) {
try {
qr.update(TransationManager.getConnection(),
"update account set money=? where id=?",
account.getMoney(), account.getId());
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
利用动态代理实现事物的统一管理确实能提高开发效率,面向切面编程的思想的核心就是动态代理,其实AOP的思想还可以用在日志管理,执行性能监控的功能,这里小编只是抛砖引玉,将小小的动态代理介绍一下。以后肯定会继续进攻这些高大上的技术。