• Spring集成MyBatis


    Spring集成MyBatis

    使用

    1. 配置数据源
    <!--配置dataSource-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"/>
            <property name="username" value="xxx"/>
            <property name="password" value="xxx"/>
        </bean>
    
    1. 配置SqlSessionFactoryBean
    <!--配置sqlSessionFactory, 这里使用了SqlSessionFacotryBean,它继承了FactoryBean接口,可以让mybatis自定义生成我们的sqlSessionFactory
    -->
        <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"/>
            <property name="typeAliasesPackage" value="myBatis_Spring.entity"/>
        </bean>
    
    1. 扫描mapper接口,并为每个mapper接口代理对象
    <!--扫描所有mapper,并生成代理对象-->
        <bean id="mapperScannerConfigurer"		class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="myBatis_Spring.mapper"/>
        </bean>
    
    对象说明

    FactoryBean: 工厂Bean用于自定义生成Bean对象。当在ioc 中配置FactoryBean 的实例时,最终通过bean id 对应的是FactoryBean.getObject()实例,而非FactoryBean 实例本身

    SqlSessionFactoryBean: 生成SqlSessionFactory 实例,该为单例对像,作用于整个应用生命周期。

    MapperScannerConfigurer: 扫描我们写的mapper接口,并在spring容器初始化时为我们创建一个单例的Mapper代理对象。

    线程安全问题

    ​ 和原生mybatis不同的是,创建出来的mapper是一个单例对象,按理说会存在线程安全问题。但是spring帮我们解决了这一点,当spring容器初始化的时候,会生成mapper的一个代理对象。每当mapper调用它的任何一个方法,都会经过代理对象的invoke方法。在这个invoke方法中,每次都会创建一个新的SqlSession,当这个方法调用完成后SqlSession方法也会随之销毁或者释放。

    /*
    SqlSessionTemplate > SqlSessionInterceptor > invoke()
    */
    private class SqlSessionInterceptor implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          	//获取SqlSession对象
            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;
        ....
        ....
    

    一级缓存还会生效吗

    如果每次执行一个查询都会创建一个新的SqlSession,那么一级缓存不是不起作用了吗?

    确实如此,但是当我们Service层方法加了@Transactional后,在这个有事务的方法内,第一次查询数据库,会把新建的SqlSession对象存入ThreadLoacl中,下一次进行查询时会先判断这个ThreadLocal中是否有对应的SqlSession对象。

    /*
    SqlSessionUtils > getSqlSession()
    */
    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);
    
        //从ThreadLoacl中获取SqlSession
        SqlSession session = sessionHolder(executorType, holder);
        if (session != null) {
          return session;
        }
    
        LOGGER.debug(() -> "Creating a new SqlSession");
        //如果ThreadLoacl中没有的话就创建一个新的SqlSession
        session = sessionFactory.openSession(executorType);
    
        registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
    
        return session;
      }
    
  • 相关阅读:
    计算机视觉、机器学习相关领域论文和源代码大集合【转载】
    一试真伪:可以在12306上选择上中下卧铺吗
    给企业研发人员列一张数学清单【转载】
    向“生物力学之父”冯元桢先生学习什么?【转载】
    热消融影像引导
    Computer assisted surgery
    ASM, AAM
    Linux 下编译安装MySQL
    Linux下搭建FTP服务器
    自己瞎捣腾的Win7下Linux安装之路-----理论篇
  • 原文地址:https://www.cnblogs.com/zcr-xiaozhai/p/14037192.html
Copyright © 2020-2023  润新知