与Guice和JDBC的事务-解决方案讨论
在我的应用程序中,我需要将纯JDBC与Guice一起使用。但是,Guice不提供任何内置支持来管理事务。guice persist只提供基于JPA的支持,我不能使用JPA 因此,我尝试实现一个简单的解决方案,用Guice和JDBC管理事务。以下是第一个版本:与Guice和JDBC的事务-解决方案讨论,jdbc,transactions,guice,transactionmanager,Jdbc,Transactions,Guice,Transactionmanager,在我的应用程序中,我需要将纯JDBC与Guice一起使用。但是,Guice不提供任何内置支持来管理事务。guice persist只提供基于JPA的支持,我不能使用JPA 因此,我尝试实现一个简单的解决方案,用Guice和JDBC管理事务。以下是第一个版本: 使用TransactionHolder存储每个线程的事务 公共类JdbcTransactionHolder{ private static ThreadLocal<JdbcTransaction> currentTransact
private static ThreadLocal<JdbcTransaction> currentTransaction = new ThreadLocal<JdbcTransaction>();
public static void setCurrentTransaction(JdbcTransaction transaction) {
currentTransaction.set(transaction);
}
public static JdbcTransaction getCurrentTransaction() {
return currentTransaction.get();
}
public static void removeCurrentTransaction() {
currentTransaction.remove();
}
}private final static org.slf4j.Logger logger = LoggerFactory.getLogger(JdbcDataSource.class);
private DataSource dataSource;
public JdbcDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return dataSource.getLogWriter();
}
@Override
public int getLoginTimeout() throws SQLException {
return dataSource.getLoginTimeout();
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return dataSource.getParentLogger();
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
this.dataSource.setLogWriter(out);
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
this.dataSource.setLoginTimeout(seconds);
}
@Override
public boolean isWrapperFor(Class<?> arg0) throws SQLException {
return this.isWrapperFor(arg0);
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return this.unwrap(iface);
}
@Override
public Connection getConnection() throws SQLException {
JdbcTransaction transaction = JdbcTransactionHolder.getCurrentTransaction();
if(transaction != null) {
// we get the connection from the transaction
logger.debug("Transaction exists for the thread: {}.", Thread.currentThread());
return transaction.getConnection();
}
Connection conn = this.dataSource.getConnection();
conn.setAutoCommit(false);
return conn;
}
@Override
public Connection getConnection(String username, String password)
throws SQLException {
JdbcTransaction transaction = JdbcTransactionHolder.getCurrentTransaction();
if(transaction != null) {
// we get the connection from the transaction
logger.debug("Transaction exists for the thread: {}.", Thread.currentThread());
return transaction.getConnection();
}
return this.dataSource.getConnection(username, password);
}
private final static Logger logger = LoggerFactory.getLogger(TransactionalMethodInterceptor.class);
@Inject
private JdbcTransactionManager transactionManager;
@Override
public Object invoke(MethodInvocation method) throws Throwable {
try {
// Start the transaction
transactionManager.begin();
logger.debug("Start to invoke the method: " + method);
Object result = method.proceed();
logger.debug("Finish invoking the method: " + method);
transactionManager.commit();
return result;
} catch (Exception e) {
logger.error("Failed to commit transaction!", e);
try {
transactionManager.rollback();
}
catch(Exception ex) {
logger.warn("Cannot roll back transaction!", ex);
}
throw e;
}
}
}bind(DataSource.class).toProvider(DataSourceProvider.class).in(Scopes.SINGLETON);
bind(TransactionManager.class).to(JdbcTransactionManager.class);
TransactionalMethodInterceptor transactionalMethodInterceptor = new TransactionalMethodInterceptor();
requestInjection(transactionalMethodInterceptor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(Transactional.class), transactionalMethodInterceptor);
bind(TestDao.class).to(JdbcTestDao.class);
bind(TestService.class).to(TestServiceImpl.class);
谢谢。记住一件事:不使用RuntimeException,而是需要定义特定于处理错误的异常。
private final static Logger logger = LoggerFactory.getLogger(TransactionalMethodInterceptor.class);
@Inject
private JdbcTransactionManager transactionManager;
@Override
public Object invoke(MethodInvocation method) throws Throwable {
try {
// Start the transaction
transactionManager.begin();
logger.debug("Start to invoke the method: " + method);
Object result = method.proceed();
logger.debug("Finish invoking the method: " + method);
transactionManager.commit();
return result;
} catch (Exception e) {
logger.error("Failed to commit transaction!", e);
try {
transactionManager.rollback();
}
catch(Exception ex) {
logger.warn("Cannot roll back transaction!", ex);
}
throw e;
}
}
bind(DataSource.class).toProvider(DataSourceProvider.class).in(Scopes.SINGLETON);
bind(TransactionManager.class).to(JdbcTransactionManager.class);
TransactionalMethodInterceptor transactionalMethodInterceptor = new TransactionalMethodInterceptor();
requestInjection(transactionalMethodInterceptor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(Transactional.class), transactionalMethodInterceptor);
bind(TestDao.class).to(JdbcTestDao.class);
bind(TestService.class).to(TestServiceImpl.class);