首页 > 其他分享 >MyBatis good

MyBatis good

时间:2022-12-20 23:07:08浏览次数:60  
标签:good sqlSessionFactory mybatis SqlSession session new MyBatis org

增加下面的配置,就会把spring-mybatis中debug的日志也打印出来

mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl


Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2194ede9] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@25ab6d03] will not be managed by Spring
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4a88fe6e] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5aeb8427] will not be managed by Spring
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4a88fe6e]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@df3739] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5aeb8427] will not be managed by Spring
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2194ede9]
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@df3739]

 

 

org.mybatis.spring.transaction.SpringManagedTransaction#openConnection

/**
* Gets a connection from Spring transaction manager and discovers if this {@code Transaction} should manage
* connection or let it to Spring.
* <p>
* It also reads autocommit setting because when using Spring Transaction MyBatis thinks that autocommit is always
* false and will always call commit/rollback so we need to no-op that calls.
*/
private void openConnection() throws SQLException {
this.connection = DataSourceUtils.getConnection(this.dataSource);
this.autoCommit = this.connection.getAutoCommit();
this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);

LOGGER.debug(() -> "JDBC Connection [" + this.connection + "] will"
+ (this.isConnectionTransactional ? " " : " not ") + "be managed by Spring");
}

org.mybatis.spring.SqlSessionUtils#getSqlSession(org.apache.ibatis.session.SqlSessionFactory, org.apache.ibatis.session.ExecutorType, org.springframework.dao.support.PersistenceExceptionTranslator)

/**
* Gets an SqlSession from Spring Transaction Manager or creates a new one if needed. Tries to get a SqlSession out of
* current transaction. If there is not any, it creates a new one. Then, it synchronizes the SqlSession with the
* transaction if Spring TX is active and <code>SpringManagedTransactionFactory</code> is configured as a transaction
* manager.
*
* @param sessionFactory
* a MyBatis {@code SqlSessionFactory} to create new sessions
* @param executorType
* The executor type of the SqlSession to create
* @param exceptionTranslator
* Optional. Translates SqlSession.commit() exceptions to Spring exceptions.
* @return an SqlSession managed by Spring Transaction Manager
* @throws TransientDataAccessResourceException
* if a transaction is active and the {@code SqlSessionFactory} is not using a
* {@code SpringManagedTransactionFactory}
* @see SpringManagedTransactionFactory
*/
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {

notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);

SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);

SqlSession session = sessionHolder(executorType, holder);
if (session != null) {
return session;
}

LOGGER.debug(() -> "Creating a new SqlSession");
session = sessionFactory.openSession(executorType);

registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);

return session;
}

org.mybatis.spring.SqlSessionUtils#registerSessionHolder

/**
* Register session holder if synchronization is active (i.e. a Spring TX is active).
*
* Note: The DataSource used by the Environment should be synchronized with the transaction either through
* DataSourceTxMgr or another tx synchronization. Further assume that if an exception is thrown, whatever started the
* transaction will handle closing / rolling back the Connection associated with the SqlSession.
*
* @param sessionFactory
* sqlSessionFactory used for registration.
* @param executorType
* executorType used for registration.
* @param exceptionTranslator
* persistenceExceptionTranslator used for registration.
* @param session
* sqlSession used for registration.
*/
private static void registerSessionHolder(SqlSessionFactory sessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator, SqlSession session) {
SqlSessionHolder holder;
if (TransactionSynchronizationManager.isSynchronizationActive()) {
Environment environment = sessionFactory.getConfiguration().getEnvironment();

if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {
LOGGER.debug(() -> "Registering transaction synchronization for SqlSession [" + session + "]");

holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
TransactionSynchronizationManager.bindResource(sessionFactory, holder);
TransactionSynchronizationManager
.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
holder.setSynchronizedWithTransaction(true);
holder.requested();
} else {
if (TransactionSynchronizationManager.getResource(environment.getDataSource()) == null) {
LOGGER.debug(() -> "SqlSession [" + session
+ "] was not registered for synchronization because DataSource is not transactional");
} else {
throw new TransientDataAccessResourceException(
"SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");
}
}
} else {
LOGGER.debug(() -> "SqlSession [" + session
+ "] was not registered for synchronization because synchronization is not active");
}

}

org.mybatis.spring.SqlSessionUtils#closeSqlSession

/**
* Checks if {@code SqlSession} passed as an argument is managed by Spring {@code TransactionSynchronizationManager}
* If it is not, it closes it, otherwise it just updates the reference counter and lets Spring call the close callback
* when the managed transaction ends
*
* @param session
* a target SqlSession
* @param sessionFactory
* a factory of SqlSession
*/
public static void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory) {
notNull(session, NO_SQL_SESSION_SPECIFIED);
notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);

SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if ((holder != null) && (holder.getSqlSession() == session)) {
LOGGER.debug(() -> "Releasing transactional SqlSession [" + session + "]");
holder.released();
} else {
LOGGER.debug(() -> "Closing non transactional SqlSession [" + session + "]");
session.close();
}
}

 

 

 

命名解析:为了减少输入量,MyBatis 对所有的命名配置元素(包括语句,结果映射,缓存等)使用了如下的命名解析规则。

  • 完全限定名(比如“com.mypackage.MyMapper.selectAllThings”)将被直接查找并且找到即用。
  • 短名称(比如“selectAllThings”)如果全局唯一也可以作为一个单独的引用。如果不唯一,有两个或两个以上的相同名称(比如“com.foo.selectAllThings ”和“com.bar.selectAllThings”),那么使用时就会收到错误报告说短名称是不唯一的,这种情况下就必须使用完全限定名。

对于像 BlogMapper 这样的映射器类(Mapper class)来说,还有另一招来处理。它们的映射的语句可以不需要用 XML 来做,取而代之的是可以使用 Java 注解。比如,上面的 XML 示例可被替换如下:

package org.mybatis.example;
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}

对于简单语句来说,注解使代码显得更加简洁,然而 Java 注解对于稍微复杂的语句就会力不从心并且会显得更加混乱。因此,如果你需要做很复杂的事情,那么最好使用 XML 来映射语句。

选择何种方式以及映射语句的定义的一致性对你来说有多重要这些完全取决于你和你的团队。换句话说,永远不要拘泥于一种方式,你可以很轻松的在基于注解和 XML 的语句映射方式间自由移植和切换。

 

​http://www.mybatis.org/mybatis-3/zh/getting-started.html​

 

说明:Java-based Config。

不是通过 mybatis 的 SqlSessionFactoryBuilder 来创建 SqlSessionFactory ,而是通过 mybatis-spring 的 SqlSessionFactoryBean 来获取。

1、首先要有一个DataSource 

需要注意,事务管理器也在这里注册。(mybatis-spring插件会自动调用该事务管理器)  

@Bean(name = "transactionManager")
public DataSourceTransactionManager dataSourceTransactionManager() {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(this.dataSource());
return dataSourceTransactionManager;
}

 

2、然后,注册SqlSessionFactoryBean(或者SqlSessionFactory,二选一,内容一致)。如下:

@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(this.dataSource());
// sqlSessionFactoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml")); // 这里可以通过mybatis-config.xml 来设置 typeAliasPackage和mapper。
// Resource[] mapperLocations = new Resource[] { new ClassPathResource("com.expert.dao") }; // 这个和@MapperScan冲突吗?这个设置有问题。
// sqlSessionFactoryBean.setMapperLocations(mapperLocations);//<mappers>
sqlSessionFactoryBean.setTypeAliasesPackage(PojoBasePackage);
// sqlSessionFactoryBean.setCache(cache);
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
// It can be specified a Configuration instance directly without MyBatis XML configuration file.
sqlSessionFactory.getConfiguration().setMapUnderscoreToCamelCase(true);// 开启驼峰映射
sqlSessionFactory.getConfiguration().setCacheEnabled(true);
sqlSessionFactory.getConfiguration().setLazyLoadingEnabled(true);
sqlSessionFactory.getConfiguration().setAggressiveLazyLoading(false);
// Class<Object> logImpl = sqlSessionFactory.getConfiguration().getTypeAliasRegistry().resolveAlias("SLF4J");
sqlSessionFactory.getConfiguration().setLogImpl(Slf4jImpl.class);// logImpl
sqlSessionFactory.getConfiguration().setLogPrefix("###SPRING_BOOT###MYBATIS###");
sqlSessionFactory.getConfiguration().setDefaultExecutorType(ExecutorType.REUSE);
sqlSessionFactory.getConfiguration().setUseGeneratedKeys(true);
return sqlSessionFactory;
}

这里还设置了一堆参数。需要注意的是,

①设置了 TypeAliasesPackage 

②设置了 Configuration 。

③mybatis-spring会自动创建 Configuration 对象,所以通过 sqlSessionFactory.getConfiguration() 即可获取并进行设置。

 

3、再注册一个 SqlSessionTemplate,这是 mybatis-spring 的核心。

@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE) // 多例?
public SqlSessionTemplate sqlSessionTemplate() throws Exception {
return new SqlSessionTemplate(this.sqlSessionFactory());
}

 

4、设置mapper的位置,有两种方法。

①推荐这种,简单。

@Configuration
@MapperScan(basePackages = { "com.expert.dao" })
public class DruidDataSourceConfig{
// ...
}

@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage(DaoBasePackage);
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
return mapperScannerConfigurer;
}

 

至此,已可以成功运行。

 

但是,还有更简单的方法,那就是 MyBatis-Spring-Boot-Starter 。使用该Starter时,会自动查找DataSource,并自动创建SqlSessionFactoryBean 和 SqlSessionTemplate。所以,只需要设置mapper所在的位置和别名所在的包即可。

 

见 ​​MyBatis-Spring-Boot 使用总结​​ 。 


@ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
public class MybatisProperties {

public static final String MYBATIS_PREFIX = "mybatis";
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnBean(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration {

​https://github.com/mybatis/spring-boot-starter/blob/master/mybatis-spring-boot-autoconfigure/src/main/java/org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.java​

 

Caused by: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.retry.business.repository.mapper.RetryTaskDOMapper.findAllFailByBizId. please check URL [jar:file:/app.jar!/BOOT-INF/classes!/mapper/retry/RetryTaskDOMapper.xml] and URL [jar:file:/app.jar!/BOOT-INF/classes!/mapper/retry/RetryTaskDOMapper.xml]

解决办法:删除RetryTaskDOMapper.xml文件中重复的id为findAllFailByBizId 一个sql就可以了
原因:
意思是这个sql绑定了一个ResultMap了,不能重复绑定。

 



标签:good,sqlSessionFactory,mybatis,SqlSession,session,new,MyBatis,org
From: https://blog.51cto.com/u_15147537/5956952

相关文章

  • mybatis.generator.configurationFile
    mybatis.generator.configurationFile有一个更好的配置方法,可以不用在generateConfig.xml里面写死驱动的地址:如果你的mybatis连接也是在pom.xml里面配置的话,那么可以在pom.......
  • mybatis拦截器 (拦截器不生产)
    背景:在一些需求下,使用拦截器会大大简化工作量也更加灵活:在项目中,要更新数据表的审计字段,比如create_time,creator,update_time,updator,这些字段,如果每一个表对应......
  • Mybatis-plus
    1.Mybatis-plusMybatis-plus相关文档https://weishao-996.github.io/2022/10/25/黑马程序员-Mybatis-Plus/Mybatis代码生成器https://weishao-996.github.io/2022/1......
  • 最小二乘法 good
    最小二乘法也称为最小平方法,是一种数据优化技术,它通过最小化误差的平方和寻找数据的最佳函数匹配。最小二乘法最初由高尔顿在创立回归分析的时候提出,现在已经成为探索变量间......
  • Spring 4 and MyBatis Java Config
    TL;DRWiththeJavaConfigenhancementsinSpring4,younolongerneedxmltoconfigureMyBatisforyourSpringapplication.Usingthe ​​@MapperScan​​​ann......
  • 【sping框架】 springboot框架中如何整合mybatis框架?
    1.引入依赖spring-boot-stater-webmysql相关mysql驱动druid数据源mybatis相关的(mybatis-spring-boot-stater)依赖(mybatismybatis-spring)2.书写配置 a.开启......
  • MyBatis打印SQL语句
     1.Spring+MyBatis这种框架一般还使用的XML配置,所以要在MyBatis的配置文件中加以下信息,就可以打印日志了。<configuration><settings><!--打......
  • 使用Akka、Kafka和ElasticSearch等构建分析引擎 -- good
    本文翻译自​​BuildingAnalyticsEngineUsingAkka,Kafka&ElasticSearch​​,已获得原作者SatendraKumar和网站授权。在这篇文章里,我将和大家分享一下我用Scala、Akka......
  • mybatis resultMap collection聚合String
    背景主表index_dict_data内容表index_dict_cn_name期望输出数据结构:即联表之后根据indexId聚合,然后将cnName字段聚合到一个List<String>中[{"in......
  • 5.1 入门整合案例(SpringBoot+Spring-data-elasticsearch) ---- good
    本节讲解SpringBoot与Spring-data-elasticsearch整合的入门案例。一、环境搭建新建maven项目,名字随意pom.xml<parent><groupId>org.springframework.boot</groupId><artifac......