Spring入门二:整合mybatis

一、SM思路分析

1、引入核心依赖及相关依赖:

 spring(略)、mybatis、mysql、mybatis-spring(减少自己实现FactoryBean接口)、druid
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.22</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.6</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.6</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.5</version>
</dependency>

2、如何整合?

通过spring框架接管mybatis框架中核心对象的创建

3、mybatis中的核心对象

SqlSessionFactory

4、SM整合实质

通过spring框架接管mybatis中核心的SqlSessionFactory对象的创建。Spring如何管理SqlSessionFactory对象的创建?SqlSessionFactory是一个接口类型的复杂对象。

is=Resource.getResourceAsStrem("mybatis-config.xml);

sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);

1)手动配置:

(0)在类路径下配置mybatis-config.xml的数据源:

<dataSource type="POOLED">
    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/springboot?characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
    <property name="username" value="root"/>
    <property name="password" value="xroot"/>
</dataSource>

1)在spring中可以新建类SqlSessionFactoryBean实现FactoryBean接口

//自定义SqlSessionFactory
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory> {
    private String configLocations;//通过参数注入配置文件名

    public void setConfigLocations(String configLocations) {
        this.configLocations = configLocations;
    }

    public SqlSessionFactory getObject() throws Exception {
        //InputStream rs = Resources.getResourceAsStream("mybatis-config.xml");
        InputStream rs = Resources.getResourceAsStream(configLocations);
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(rs);
        return build;
    }

    public java.lang.Class<?> getObjectType() {
        return SqlSessionFactory.class;
    }

    public boolean isSingleton() {
        return true;
    }
}

2)工厂管理SqlSessionFactory

<bean id="sqlSessionFactory" class="com.icucoder.SqlSessionFactoryBean">
   <property name="configLocations" value="mybatis-config.xml"/>
</bean>

3)工厂获取

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) context.getBean("sqlSessionFactory");
System.out.println(sqlSessionFactory.openSession());

2)spring自动配置(使用mybatis-spring依赖:Mybatis-spring.jar封装了SqlSessionFactory对象的创建)

0)加入mybatis-spring依赖、druid依赖(简单类型)

1)工厂管理SqlSessionFactory并配置druid数据源对象dataSource

<!--创建数据源对象 druid c3p0 dbcp-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/springboot?characterEncoding=UTF-8"/>
    <property name="username" value="root"/>
    <property name="password" value="xroot"/>
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!--依赖数据源-->
    <property name="dataSource" ref="dataSource"/>
    <!--依赖mapper文件注册-->
    <property name="mapperLocations">
        <array>
            <value>com/icucoder/mapper/UserDaoMapper.xml</value>
        </array>
    </property>
</bean>

 上述配置每创建一个Mapper文件,需要配置一个array,可以使用mapperLocations配置某个具体类路径下xml的自动扫描。

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 依赖数据源 -->
    <property name="dataSource" ref="dataSource"/>
    <!-- 注入mapper通用方式 -->
    <property name="mapperLocations" value="classpath:mapper/*.xml"></property>
    <!-- 取别名 -->
    <property name="typeAliasesPackage" value="com.icucoder.entity"></property>
</bean>
 

2)工厂获取

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) context.getBean("sqlSessionFactory");
System.out.println(sqlSessionFactory.openSession());

二、DAO层开发

1、建实体类(前提数据库中有表)

public class User {
    private Integer id;
    private String name;
    private Integer age;
    private Integer email;
    //省略有参和无参构造 setter和getter方法
}

2、DAO接口

public interface UserDao {
    List<User>findAll();
}

3、开发mapper(dao的实现类)

<mapper namespace="com.icucoder.dao.UserDao">
    <select id="findAll" resultType="com.icucoder.entity.User">
        select id,name,age,email
        from user
  </select>
</mapper>

4、spring配置文件中注册mapper配置文件

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--依赖数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--依赖mapper文件注册-->
        <property name="mapperLocations">
            <array>
                <value>classpath:mapper/UserDaoMapper.xml</value>
            </array>
        </property>
</bean>

上述配置每创建一个Mapper文件,需要配置一个array,可以使用mapperLocations配置某个具体类路径下xml的自动扫描(见上)。

5、启动工厂获SqlSessionfactory

1)手动获取DAO:

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) context.getBean("sqlSessionFactory");
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
System.out.println(userDao.findAll());

 2)使用MapperFactoryBean获取DAO:

1)在MapperFactoryBean中注入SqlSessionFactory和Dao路径

<!--创建Dao组件类-->
<bean id="userDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    <!--注入dao类型-->
    <property name="mapperInterface" value="com.icucoder.dao.UserDao"/>
</bean>

 上述配置每创建一个Dao组件类,需要配置一个bean,可以使用MapperScannerConfigurer配置某个具体累计下dao的自动扫描

<!--创建Dao组件类-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>>
    <!--扫描DAO接口所在包-->
    <property name="basePackage" value="com.icucoder.dao"/>
</bean>

 2)调用bean

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserDao userDao = (UserDao) context.getBean("userDao");
System.out.println(userDao.findAll());

三、Service层事务控制

在上述dao的基础上:

1、常规做法(使用默认的事务)

1)创建Service及其实现类

//UserService省略
public class UserServiceImpl implements UserService {
    private UserDao userDao;
    //private DataSource dataSource;//手动注入 dataSoruce无法保证service与dao层事务的连接性
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public List<User> findAll() {
        return userDao.findAll();
    }
}

 2)在spring配置文件中管理service组件

<bean id="userService" class="com.icucoder.service.impl.UserServiceImpl">
   <property name="userDao" ref="userDao"/>
</bean>

 3)调用Bean

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
System.out.println(userService.findAll());

2、mybatis框架中事物控制分析

SqlSession,提交:sqlSession.commit);回滚:sqlSessioin.rollback();

真正负责数据库事物控制的对象:Connection(java.sql.Connection)对象。

注意:数据源DruidDataSource是一个连接池,里面都是Connection对象。

Connection conn=DruidDataSource().getConnection();

可以在业务层手动注入dataSource对象来控制事务,但是无法保证业务层(Sevice)和Dao事务的连接性。

3、数据源事务管理器:DataSourceTransactionManager

在spring和mybatis框架中提供了一个类DataSourceTransactionManager(数据源事务管理器)来全局创建一个事务管理器,用来统一调度业务层当前线程使用连接对象和DAO层实现连接对象一致。它依赖于数据源。

在spring.xml文件中添加DataSourceTransactionManager的bean。

<!---数据源事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

4、给现有业务层加入事务控制(手动配置事务)

 1)重写service实现类

public class UserServiceImpl implements UserService {
    private PlatformTransactionManager transactionManager;

    public void setTransactionManager(PlatformTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public List<User> findAll() {
        return userDao.findAll();
    }

    @Override
    public void save(User user) {
        TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
        TransactionStatus status = transactionManager.getTransaction(transactionDefinition);

        //控制事物
        try {
            //处理业务
            //调用业务
            userDao.save(user);
            int i=1/0;
            transactionManager.commit(status);
            System.out.println("save success");
        }catch (Exception e){
            e.printStackTrace();
            transactionManager.rollback(status);
        }
    }
}

 2)在spring配置文件的service的bean标签中注入数据源事务管理器

<bean id="userService" class="com.icucoder.service.impl.UserServiceImpl">
    <property name="userDao" ref="userDao"/>
    <property name="transactionManager" ref="transactionManager"/>
</bean>

3)调用Bean

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
User user=new User(7,"test",12,"admin@qq.com");
System.out.println(user);
userService.save(user);

四、Service层事务控制优化(自动配置事务)

1、spring中处理事务的两种方式

编程式事务处理:通过在业务层中农注入事务管理器对象,然后通过编码的方式进行事务控制。

声明式事务处理:通过利用aop切面编程进行事务控制,并对事务属性在配置文件中完成细粒度配置。

2、给现有业务层加入事务控制(手动配置事务优化)

开发一个基于事务的通知(环绕通知)TransactionAdvice实现MethodInterceptor。

1)创建环绕通知

2)配置切面

3)使用环绕通知

3、给现有业务层加入事务控制(自动配置事务-使用aop)

 spring框架提供了<tx:advice/>标签,该标签可以根据事务管理器创建一个基于事务环绕通知对象,并对业务层方法进行细粒度事务控制。

 1)在spring配置文件中加入声明式事务管理

<!--声明式事务管理-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!--事务细粒度控制,不控制则事务不生效-->
    <tx:attributes>
        <tx:method name="save*"/>
    </tx:attributes>
</tx:advice>

2)配置切面

<!--配置事务切面-->
<aop:config>
    <aop:pointcut id="pc" expression="within(com.icucoder.service.impl.*ServiceImpl)"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>

 3)重写service实现类

public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public List<User> findAll() {
        return userDao.findAll();
    }

    @Override
    public void save(User user) {
        //控制事物
        //处理业务
        //调用业务
        userDao.save(user);
        int i = 1 / 0;
        System.out.println("save");
    }
}

4、给现有业务层加入事务控制(自动配置事务-开启注解式事务驱动管理器)

1)在spring配置文件中加入tx:annotation-driven,这样就不要<tx:advice/>和<aop:config>,可以直接使用注解@Transactional

<!--开启注解式事务驱动管理器@Transactional-->
<tx:annotation-driven transaction-manager="transactionManager"/>

2)重写service实现类

@Transactional
public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public List<User> findAll() {
        return userDao.findAll();
    }

    @Override
    public void save(User user) {
        //控制事物
        //处理业务
        //调用业务
        userDao.save(user);
        int i = 1 / 0;
        System.out.println("save");

    }
}
 注:
也可以使用easycode直接对数据的表生成entity,controller,service,dao,mapper,无需任何编码。
 

如果你真心觉得文章写得不错,而且对你有所帮助,那就不妨小小打赏一下吧,如果囊中羞涩,不妨帮忙“推荐"一下,您的“推荐”和”打赏“将是我最大的写作动力!

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接.
qq群 微信
原文地址:https://www.cnblogs.com/hoaprox/p/14565714.html