1.SqlSessionTemplate 是如何保证线程安全
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {
notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
notNull(executorType, "Property 'executorType' is required");
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());
}
以上代码sqlSession通过动态代理的方式创建,当实际调用sqlSession中的接口,该调用则被导向SqlSessionInterceptor的invoke方法。
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
}
可以在invoke方法中看到sqlSession 通过getSession产生。也就是说每次调用的sqlSession中的接口,sqlSession都是当前线程独有的。如果不是很明白动态代理的话请看下面
2.动态代理demo
car
public interface Car {
void describe();
}
BMW
public class BMW implements Car {
public void describe() {
System.out.println("宝马 " + UUID.randomUUID());
}
}
Jeep
public class Jeep implements Car {
public void describe() {
System.out.println("jeep " + UUID.randomUUID());
}
}
CarProxy
public class CarProxy implements InvocationHandler {
private Random random = new Random();
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
int randomInt = random.nextInt(10);
Car car;
if (randomInt < 5) { //模拟调用失败情况
car = new BMW();
} else {
car = new Jeep();
}
method.invoke(car, args);
return null;
}
}
Xlient
public class Xlient {
private Car car;
public static void main(String[] args) {
Xlient xlient = new Xlient();
xlient.test();
}
private void test() {
Car car = (Car) Proxy.newProxyInstance(Car.class.getClassLoader(), new Class[]{Car.class}, new CarProxy());
for (int i = 0; i < 100; i++) {
car.describe();
}
}
}
运行以上代码结果
jeep 8870e1f0-e5fa-4a42-a1dc-4b8bfa07789c
jeep 01977d67-1faa-49ed-aec1-c9c41b767fed
jeep 15aa16d5-8c5f-478b-aaac-804627f77057
宝马 ee38f7e6-b2df-4385-b57f-9ded3384642a
jeep 8870e1f0-e5fa-4a42-a1dc-4b8bfa07789c
jeep 01977d67-1faa-49ed-aec1-c9c41b767fed
jeep 15aa16d5-8c5f-478b-aaac-804627f77057
宝马 ee38f7e6-b2df-4385-b57f-9ded3384642a
虽然car是一个全局变量但是通过动态代理产生的car每次都是一个全新的对象,这个就和sqlSession的产生是一样的效果。所以保证了线程安全,sqlSession通过SqlSessionInterceptor产生、释放等操作