MyBatis深入理解和使用-MyBatis事务管理
事务管理
JDBC事务
public static boolean insert(Test test) throws SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=utf-8&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC", "test", "123456");
// 自动提交设置为false
connection.setAutoCommit(false);
preparedStatement = connection.prepareStatement("INSERT INTO test VALUES (?,?,?)");
if (null != test.getId()) {
preparedStatement.setInt(1, test.getId());
} else {
preparedStatement.setNull(1, INTEGER);
}
preparedStatement.setInt(2, test.getNums());
preparedStatement.setString(3, test.getName());
preparedStatement.execute();
connection.commit();
return true;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (null != connection) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return true;
}
MyBatis自带事务
SqlSession --> Exxecutor --> Transaction --> Connection
之后就是JDBC的处理逻辑
Mybatis-Spring-x.x.x.jar
mapper是怎么注入进来的
XML 或者 java Config- ->MapperScannerConfigurer
--> BeanDefinitionRegistryPostProcessor
-->BeanFactoryPostProcessor
告诉Spring去加载MyBatisConfig
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
Annotation --> MapperScannerRegistrar
-->ImportBeanDefinitionRegistrar
告诉Spring去加载MyBatisConfig
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
// this check is needed in Spring 3.1
if (resourceLoader != null) {
scanner.setResourceLoader(resourceLoader);
}
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
scanner.setAnnotationClass(annotationClass);
}
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
scanner.setMarkerInterface(markerInterface);
}
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
}
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
}
scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
List<String> basePackages = new ArrayList<String>();
for (String pkg : annoAttrs.getStringArray("value")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (String pkg : annoAttrs.getStringArray("basePackages")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));
}
public interface ImportBeanDefinitionRegistrar {
void registerBeanDefinitions(AnnotationMetadata var1, BeanDefinitionRegistry var2);
}
sqlsession
的生命周期在没有@Transaction
的情况下是request/method级别的;在有@Transaction
的情况下
是@Transaction
范围内的。
Mapper
在没有spring的时候是Method
级别的,在有的时候是全局的Singleton
。
// set
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
definition.setBeanClass(this.mapperFactoryBean.getClass());
// get
Configuration configuration = getSqlSession().getConfiguration();
分页查询
逻辑分页
org.apache.ibatis.executor.resultset.DefaultResultSetHandler # handleRowValuesForSimpleResultMap
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
DefaultResultContext<Object> resultContext = new DefaultResultContext<Object>();
// 判断要跳到响应的offset对应的位置
skipRows(rsw.getResultSet(), rowBounds);
while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);
Object rowValue = getRowValue(rsw, discriminatedResultMap);
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
// 具体判断逻辑
private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
rs.absolute(rowBounds.getOffset());
}
} else {
//具体实现
for (int i = 0; i < rowBounds.getOffset(); i++) {
rs.next();
}
}
}
物理分页
拼SQL
select * from table limit 1000, 10;
扫描二维码关注公众号,回复: 5287551 查看本文章
插件
mybatis PageHelper https://github.com/pagehelper/Mybatis-PageHelper/tree/master/src/main/java/com/github/pagehelper
自定义拦截器实现分页功能,拦截点如上述拦截器描述
-
mybatis 允许您在映射语句执行过程中的某些点拦截对调用。默认情况下, mybatis 允许插件拦截方法调用:
MyBatis深入理解和使用-MyBatis缓存体系:https://blog.csdn.net/shang_xs/article/details/86656353
MyBatis深入理解和使用-TypeHandler:https://blog.csdn.net/shang_xs/article/details/86656173