Spring 数据库连接(Connection)绑定线程(Thread)的实现
2017-10-18 18:16
405 查看
最近在看spring事务的时候在想一个问题:spring中的很多bean都是单例的,是非状态的,而数据库连接是一种有状态的对象,所以spring一定在创建出connection之后在threadlocal中保存了它。今天正好有空,就看了一下源码:
代码很简单,以dataSource为key,ConnectionHolder为value存进了一个map里,而这个叫做resources的map是一个Threadlocal变量,存在于当前线程的ThreadlocalMap里。
bindResource是在DataSourceTransactionManager.doBegin()方法中被调用的,来看看这个方法
该方法的主要作用都写在注释里了,看一下就好。
/** * Bind the given resource for the given key to the current thread. * @param key the key to bind the value to (usually the resource factory) * @param value the value to bind (usually the active resource object) * @throws IllegalStateException if there is already a value bound to the thread * @see ResourceTransactionManager#getResourceFactory() */ public static void bindResource(Object key, Object value) throws IllegalStateException { Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key); Assert.notNull(value, "Value must not be null"); Map<Object, Object> map = resources.get(); // set ThreadLocal Map if none found if (map == null) { map = new HashMap<>(); resources.set(map); } Object oldValue = map.put(actualKey, value); // Transparently suppress a ResourceHolder that was marked as void... if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) { oldValue = null; } if (oldValue != null) { throw new IllegalStateException("Already value [" + oldValue + "] for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]"); } if (logger.isTraceEnabled()) { logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" + Thread.currentThread().getName() + "]"); } }
代码很简单,以dataSource为key,ConnectionHolder为value存进了一个map里,而这个叫做resources的map是一个Threadlocal变量,存在于当前线程的ThreadlocalMap里。
bindResource是在DataSourceTransactionManager.doBegin()方法中被调用的,来看看这个方法
/** * This implementation sets the isolation level but ignores the timeout. */ @Override protected void doBegin(Object transaction, TransactionDefinition definition) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; Connection con = null; try { if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) { Connection newCon = obtainDataSource().getConnection(); if (logger.isDebugEnabled()) { logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction"); } txObject.setConnectionHolder(new ConnectionHolder(newCon), true); } txObject.getConnectionHolder().setSynchronizedWithTransaction(true); con = txObject.getConnectionHolder().getConnection(); //这里设置隔离级别 Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition); txObject.setPreviousIsolationLevel(previousIsolationLevel); // Switch to manual commit if necessary. This is very expensive in some JDBC drivers, // so we don't want to do it unnecessarily (for example if we've explicitly // configured the connection pool to set it already). //这里设置自动提交由spring控制 if (con.getAutoCommit()) { txObject.setMustRestoreAutoCommit(true); if (logger.isDebugEnabled()) { logger.debug("Switching JDBC Connection [" + con + "] to manual commit"); } con.setAutoCommit(false); } prepareTransactionalConnection(con, definition); //设置该连接现在已经有事务了 txObject.getConnectionHolder().setTransactionActive(true); int timeout = determineTimeout(definition); if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) { txObject.getConnectionHolder().setTimeoutInSeconds(timeout); } // Bind the connection holder to the thread. //这里把新连接绑定到当前线程 if (txObject.isNewConnectionHolder()) { TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder()); } } catch (Throwable ex) { if (txObject.isNewConnectionHolder()) { DataSourceUtils.releaseConnection(con, obtainDataSource()); txObject.setConnectionHolder(null, false); } throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex); } }
该方法的主要作用都写在注释里了,看一下就好。
相关文章推荐
- 定时器中实现数据库表数据移动的功能,Exception in thread "Timer-0" isExist java.lang.NullPointerException定时器中线程报错。
- ThreadLocal为每个线程生成一个connection数据库连接对象
- ConcurrentHashMap实现数据库连接的线程安全问题
- 实现spring+mybatis+uncode dal,应用自动切换连接数据库
- 【Spring】基于c3p0连接池,实现数据库加解密连接MySQL数据库
- SpringBootl连接数据库MyBatis方式实现
- Spring 使用JdbcTemPlate的方式实现与数据库的连接
- spring 集成hibernate 连接多数据库 java BaseDao 实现
- 实现Spring连接数据库
- Spring与JDBC连接实现对数据库的增删改查
- IDE maven 创建spring boot 用hibernate 实现连接数据库
- Spring+SpringMVC+MyBatis实现数据库连接的登录功能
- hibernate+spring 连接多个数据库,动态切换(多帐套)的实现
- Spring boot + maven + hibernate 实现数据库连接、查询
- Spring-Mybatis整合时,无法连接数据库,Cannot create PoolableConnectionFactory
- Spring实现加密数据库连接
- Spring连接数据库的方式1:利用Spring实现bean属性setter方式注入
- Spring 解决线程中无法获得数据库连接
- .net通过类连接数据库并实现gridview绑定数据源
- 线程的操作 继承 thread 和实现renable 接口