事务
数据库事务
- 事务:逻辑上的多条sql的分组。该分组内的事务要么全部成功(commit),要么全部失败(rollback)。
- 数据库默认自动提交事务,即发一条sql就执行一条。
- 单条sql语句不存在事务概念。
- mysql事务语法:
start transaction
...
...
commit/rollback
- start transaction:开启事务
- rollback:回滚事务
- commit:提交事务
ACID
- 原子性:事务内的一组sql,要么全部成功,要么全部失败
- 一致性:事务执行之前和执行之后状态一致,e.g.拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
- 隔离性:多个并发事务之间相互隔离,感知不到其他事务的存在
- 持久性:事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作
隔离级别
没有隔离可能会出现的错误
- 脏读:A事务读到B事务未提交的更改数据
- 不可重复读:A事务读数据Data为状态S1, B事务将Data状态更新为S2并提交。A事务再次读Data,Data的状态
- 幻读
JDBC事务
- jdbc从数据库获取connection,默认情况下connection会自动向数据库提交它发送的sql。
- jdbc事务流程:
// 关闭自动提交,相当于mysql的start transaction
connection.setAutoCommit(false);
...
...
connection.commit()/rollback();
Spring事务
spring结合mybatis配置
class="org.mybatis.spring.mapper.MapperScannerConfigurer"
p:basePackage="com.cmbchina.ccd.pluto.babylon.*.dao"/>
id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="dataSource"
p:configLocation="classpath:mybatis-config.xml"/>
id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
transaction-manager="transactionManager"/>
<configuration>
<typeAliases>
<package name="com.cmbchina.ccd.pluto.babylon.deploy.model"/>
<package name="com.cmbchina.ccd.pluto.babylon.deploy.vo"/>
<package name="com.cmbchina.ccd.pluto.babylon.resource.model"/>
<package name="com.cmbchina.ccd.pluto.babylon.resource.vo"/>
typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="sqlserver"/>
<property name="offsetAsPageNum" value="true"/>
<property name="rowBoundsWithCount" value="true"/>
<property name="pageSizeZero" value="true"/>
<property name="reasonable" value="false"/>
<property name="supportMethodsArguments" value="false"/>
<property name="returnPageInfo" value="none"/>
plugin>
plugins>
configuration>
mybatis技术内幕
SqlSession与SqlSessionFactory(https://my.oschina.net/zudajun/blog/665956)
- SqlSessionFactory: SqlSession工厂bean,singleton,在spring启动时载入mybatis全局配置文件,创建SqlSessionFactory。
- SqlSession: 程序与数据库交互的一次会话,SqlSession封装数据库增删改查及事务方法。
- SqlSession生命周期:
- 开启spring事务:一个事务共用一个SqlSession
- 未开启spring事务:调用一次mybatis方法一个SqlSession
动态代理,自动映射Mapper的底层实现原理(https://my.oschina.net/zudajun/blog/666223)
- Mybatis中声明一个interface接口,没有编写任何实现类,Mybatis就能返回接口实例,并调用接口方法返回数据库数据
实现原理:动态代理
/**
* invocation handler of a proxy instance
* Created by z673414 on 2018/6/29.
*
* @author z673414
*/
public class MapperProxy implements InvocationHandler {
public static void main(String[] args) {
MapperProxy mapperProxy = new MapperProxy();
UserMapper userMapper = mapperProxy.newInstance(UserMapper.class);
User user = userMapper.getUserById(1);
System.out.println(user);
}
/**
* Processes a method invocation on a proxy instance and returns
* the result. This method will be invoked on an invocation handler
* when a method is invoked on a proxy instance that it is
* associated with.
*
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Exception t) {
t.printStackTrace();
}
}
return new User(1, "xiaoming");
}
/**
* 创建proxy对象
*
* @param clz
* @param
* @return
*/
public T newInstance(Class clz) {
return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[]{clz}, this);
}
}
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class mapperInterface;
private final Map methodCache;
public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map methodCache) {
......
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
private MapperMethod cachedMapperMethod(Method method) {
......
}
}
- spring事务执行:
- Spring创建MapperScannerConfigurer bean,searches recursively starting from a base package for interfaces and registers them as {@code MapperFactoryBean},将sqlSessionFactory注入每个mapperFactoryBean
- MapperFactoryBean: BeanFactory that enables injection of MyBatis mapper interfaces
- getSqlSession().getConfiguration().addMapper(this.mapperInterface)
- Spring创建SqlSessionFactory bean,解析配置文件生成Configuration对象
- Configuration生成MapperRegistry对象
- MapperRegistry getMapper()生成mapperProxyFactory
- MapperProxyFactory newInstance()生成mapperInterface的代理对象,用于调用mybatis方法,执行数据库CRUD操作