MyBatis事务的设计重点是Transaction接口;
MyBatis事务管理分为两种:
事务的配置:
事务的创建:
事务的创建是交给TransactionFactory来完成,当
JdbcTransaction实现类:Transaction的实现类,通过使用jdbc提供的方式来管理事务,通过Connection提供的事务管理方法来进行事务管理,源码如下:
public class JdbcTransaction implements Transaction {
private static final Log log = LogFactory.getLog(JdbcTransaction.class);
/* 连接**/
protected Connection connection;
/* 数据源**/
protected DataSource dataSource;
/* 事务等级**/
protected TransactionIsolationLevel level;
/* 事务提交**/
protected boolean autoCommmit;
public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
dataSource = ds;
level = desiredLevel;
autoCommmit = desiredAutoCommit;
}
public JdbcTransaction(Connection connection) {
this.connection = connection;
}
@Override
public Connection getConnection() throws SQLException {
if (connection == null) {
openConnection();
}
//返回连接
return connection;
}
@Override
public void commit() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Committing JDBC Connection [" + connection + "]");
}
//连接提交
connection.commit();
}
}
@Override
public void rollback() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Rolling back JDBC Connection [" + connection + "]");
}
//连接回滚
connection.rollback();
}
}
@Override
public void close() throws SQLException {
if (connection != null) {
resetAutoCommit();
if (log.isDebugEnabled()) {
log.debug("Closing JDBC Connection [" + connection + "]");
}
//关闭连接
connection.close();
}
}
protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
try {
//事务提交状态不一致时修改
if (connection.getAutoCommit() != desiredAutoCommit) {
if (log.isDebugEnabled()) {
log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");
}
connection.setAutoCommit(desiredAutoCommit);
}
} catch (SQLException e) {
// Only a very poorly implemented driver would fail here,
// and there's not much we can do about that.
throw new TransactionException("Error configuring AutoCommit. "
+ "Your driver may not support getAutoCommit() or setAutoCommit(). "
+ "Requested setting: " + desiredAutoCommit + ". Cause: " + e, e);
}
}
protected void resetAutoCommit() {
try {
if (!connection.getAutoCommit()) {
// MyBatis does not call commit/rollback on a connection if just selects were performed. select操作没有commit和rollback事务
// Some databases start transactions with select statements 一些数据库在select操作是会开启事务
// and they mandate a commit/rollback before closing the connection.
// A workaround is setting the autocommit to true before closing the connection.
// Sybase throws an exception here.
if (log.isDebugEnabled()) {
log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]");
}
connection.setAutoCommit(true);
}
} catch (SQLException e) {
if (log.isDebugEnabled()) {
log.debug("Error resetting autocommit to true "
+ "before closing the connection. Cause: " + e);
}
}
}
//打开连接
protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Opening JDBC Connection");
}
//从数据源中获得连接
connection = dataSource.getConnection();
if (level != null) {
connection.setTransactionIsolation(level.getLevel());
}
setDesiredAutoCommit(autoCommmit);
}
}
ManagedTransaction实现类:通过容器来进行事务管理,所有它对事务提交和回滚并不会做任何操作,源码如下:
public class ManagedTransaction implements Transaction {
private static final Log log = LogFactory.getLog(ManagedTransaction.class);
private DataSource dataSource;
private TransactionIsolationLevel level;
private Connection connection;
private boolean closeConnection;
public ManagedTransaction(Connection connection, boolean closeConnection) {
this.connection = connection;
this.closeConnection = closeConnection;
}
//数据源,事务等级及是否关闭事务
public ManagedTransaction(DataSource ds, TransactionIsolationLevel level, boolean closeConnection) {
this.dataSource = ds;
this.level = level;
this.closeConnection = closeConnection;
}
@Override
public Connection getConnection() throws SQLException {
if (this.connection == null) {
openConnection();
}
return this.connection;
}
//提交操作无效
@Override
public void commit() throws SQLException {
// Does nothing
}
//回滚操作无效
@Override
public void rollback() throws SQLException {
// Does nothing
}
@Override
public void close() throws SQLException {
if (this.closeConnection && this.connection != null) {
if (log.isDebugEnabled()) {
log.debug("Closing JDBC Connection [" + this.connection + "]");
}
//关闭连接
this.connection.close();
}
}
protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Opening JDBC Connection");
}
this.connection = this.dataSource.getConnection();
if (this.level != null) {
this.connection.setTransactionIsolation(this.level.getLevel());
}
}
}
MyBatis的缓存分为两级:一级缓存、二级缓存
MyBatis的一级缓存是SqlSession级别的缓存。在操作数据库时需要构造SqlSession对象,在对象中有一个HashMap用于存储缓存数据,不同的SqlSession之间的缓存数据区域互不影响;
一级缓存的作用域是SqlSession范围的,在同一个SqlSession中执行两次相同的sql语句时,第一次执行完毕会将查询到的数据写到缓存(内存),第二次查询时会从缓存中查询数据,不再去底层数据库查询,提高效率。
测试;
@Test
public void query(){
SqlSession sqlSession=sqlSessionFactory.openSession();
try{
User user=sqlSession.selectOne("selectUserById",1);
System.out.println(user.getUsername());
System.out.println("------------------");
User user1=sqlSession.selectOne("selectUserById",1);
System.out.println(user1.getUsername());
}catch (Exception e){
e.printStackTrace();
}finally {
sqlSession.close();
}
}
@CacheNamespace(size = 512,flushInterval = 6000)
eviction:收回策略,默认LRU,
使用二级缓存时,与查询结果映射的Java对象必须实现接口的序列化和反序列化,因为二级缓存数据存储介质多种多样,不一定在内存,有可能是硬盘或者远程服务器;
测试:
@Test
public void query(){
SqlSession sqlSession=sqlSessionFactory.openSession();
try{
User user=sqlSession.selectOne("selectUserById",1);
System.out.println(user.getUsername());
sqlSession.close();
System.out.println("------------------");
sqlSession=sqlSessionFactory.openSession();
User user1=sqlSession.selectOne("selectUserById",1);
System.out.println(user1.getUsername());
}catch (Exception e){
e.printStackTrace();
}finally {
sqlSession.close();
}
}
当关闭一级缓存时,会从二级缓存中查找,即只执行一次sql语句;