关于spring与mybatis的整合,总所周知,spring是管理组件的创建,使用和删除的,那么当spring与mybatis进行整合时,则需要将mybatis的核心对象交给spring进行管理,包括SqlsessionFactory、Sqlsession等。
这样做的好处是不需要在编写mybatis-config.xml配置文件,简化了开发。
1. 首先需要引入依赖
spring依赖 mybatis依赖 mybatis-spring依赖 mysql依赖 druid依赖
2. 编写spring的配置文件
让spring管理SqlsessionFactory对象
<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>
其中sqlSessionFactory需要数据源的配置和要对mapper进行注册。
数据源也是一个对象
<!--datasource通常有c3p0,druid,docp这些-->
<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/test?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
sqlSessionFactory可以进行优化,不用写详细的mapper文件以及起别名
<!--创建sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--依赖数据源-->
<property name="dataSource" ref="dataSource"/>
<!--注入mapper配置文件-->
<!--<property name="mapperLocations">
<array>
<value>classpath:com/baizhi/mapper/UserDAOMapper.xml</value>
<value>classpath:com/baizhi/mapper/EmpDAOMapper.xml</value>
</array>
</property>-->
<!--注入mapper文件通用方式-->
<property name="mapperLocations" value="classpath:com/baizhi/mapper/*.xml"/>
<!--注入别名相关配置 typeAliasesPackage:用来给指定包中所有类起别名 默认的别名: 类名|类名首字母小写-->
<property name="typeAliasesPackage" value="com.baizhi.entity"/>
</bean>
3.尝试获取sqlsessionFactory对象
ApplicationContext Context = new ClassPathXmlApplicationContext("spring.xml");
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) Context.getBean("sqlSessionFactory");
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> users = userDao.findAll();
users.forEach(user-> System.out.println(user));
4.进行优化
通过上述代码可以看出当我们获取到sqlSessionFactory后,我们还要通过这个对象获取sqlSession,
然后sqlsession再获取mapper(dao),才能进行数据库的操作。
因此spring和mybatis进行优化,将mapper(dao)的获取进行简化,将他们交给spring来进行管理
<!--通过mapper-spring依赖快速的获取Dao,避免先获取factory在获取dao,造成代码的冗余-->
<bean id="userDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!--注入sqlSessionFactory-->
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
<!--要创建的dao或者mapper-->
<property name="mapperInterface" value="dao.UserDao"/>
</bean>
这样就能轻松的获取到mapper(dao)进行操作。
但这样每个dao都要写一个bean,比较麻烦,因此可以使用
<!--一次项目创建项目中所有DAO对象 MapperScannerConfigurer
MapperScannerConfigurer:
默认创建对象在工厂中唯一标识: 接口的首字母小写
UserDAO=====> userDAO Userdao====> userdao
OrderDAO====> orderDAO Orderdao====> orderdao
EmpDAO ===> empDAO
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--注入sqlSessionFactory-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--扫描DAO接口所在包-->
<property name="basePackage" value="com.dao"/>
</bean>
5. sqlsessionFactory的原始获取方式。
因为spring-mybatis依赖的缘故,我们能快速的获取到sqlsessionFactory的对象。
如果没有这个依赖,我们想要获取sqlsessionFactory是要通过sqlsessionFactoryBuilder来获取的。
InputStream is = Resources.getResourceAsStream(“mybatis-config.xml”);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
因为SqlSessionFactory是接口的缘故,属于复杂对象,因此想要得到它就需要创建一个SqlSessionFactoryBean类并继承FactoryBean接口来实现。
public class SqlsessionFactoryBean implements FactoryBean<SqlSessionFactory> {
private String configLocations;
public void setConfigLocations(String configLocations) {
this.configLocations = configLocations;
}
@Override
public SqlSessionFactory getObject() throws Exception {
InputStream is = Resources.getResourceAsStream(configLocations);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
return sessionFactory;
}
@Override
public Class<?> getObjectType() {
return SqlSessionFactory.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
在spring配置文件中注册SqlsessionFactoryBean
<!--初始方式获取sqlSessionFactory的方法,因为sqlSessionFactory是接口,因此要再写一个类才能获取它-->
<bean id="sqlSessionFactory" class="sqlsession.SqlsessionFactoryBean" >
<property name="configLocations" value="mybatis-config.xml"/>
</bean>
通过这样的方式就能获取sqlSessionFactory对象了。
6.service层中进行事务的管理(编程方式)
在spring和mybatis框架中,提供了一个类DataSourceTransactionManager用来通一调度业务层使用的线程和dao层使用的线程一致。
<!--数据源事务管理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源对象-->
<property name="dataSource" ref="dataSource"/>
</bean>
为serviceImpl添加TransactionManager
private PlatformTransactionManager transactionManager;
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
业务层编写
@Override
public void save(User user) {
//创建事务配置对象
TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
//获取事务状态
TransactionStatus status = transactionManager.getTransaction(transactionDefinition);
try {
int i = 1/0;
userDao.save(user);
transactionManager.commit(status);
} catch (Exception e) {
e.printStackTrace();
transactionManager.rollback(status);
}
}
7.使用AOP思想来处理事务(声明方式)
开发基于事务的环绕通知
首先创建基于环绕事务的类
public class TransactionAdvice implements MethodInterceptor {
private PlatformTransactionManager platformTransactionManager;
public void setPlatformTransactionManager(PlatformTransactionManager platformTransactionManager) {
this.platformTransactionManager = platformTransactionManager;
}
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("进入事务管理");
//创建事务配置对象
TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
//获取事务状态
TransactionStatus status = platformTransactionManager.getTransaction(transactionDefinition);
try {
Object result = methodInvocation.proceed();
platformTransactionManager.commit(status);
return result;
} catch (Exception e) {
e.printStackTrace();
platformTransactionManager.rollback(status);
}
return null;
}
}
然后再spring配置文件中配置事务类以及切面,并且建立联系
<!--数据源事务管理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源对象-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置事务环绕通知类-->
<bean id="tx" class="transaction.TransactionAdvice" >
<property name="platformTransactionManager" ref="transactionManager" />
</bean>
<!--配置事务的切面-->
<aop:config>
<aop:pointcut id="pc" expression="execution(* service.UserServiceImpl2.*(..))"/>
<aop:advisor advice-ref="tx" pointcut-ref="pc" />
</aop:config>
完成
8.spring对声明式事务的优化
spring框架提供了 tx:advice标签
作用
1.可以根据事务管理器创建一个基于事务的环绕通知对象,就不用自己写了
2.tx:advice标签可以对事务进行细粒度控制,即是细化事务,例如查询不需要事务处理
<!--创建一个基于事务管理器的事务环绕通知类-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
</tx:advice>
配置切面
<aop:config>
<aop:pointcut id="pc" expression="execution(* service.UserServiceImpl2.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc" />
</aop:config>
完成上述两步后可以说已经为service添加了事务,但由于没有进行细化,因此spring将不会进行回滚的操作,即需要进一步的配置spring的事务环绕通知类,告诉spring如何处理事务。
<!--创建一个基于事务管理器的事务环绕通知类-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*"/>
</tx:attributes>
</tx:advice>
9.SM整合步骤
引入依赖
建表
建实体类
Dao接口
Mapper配置文件
service接口
service接口实现类
编写SM整合配置spring.xml或者ApplicationContext.xml
10.整合步骤的优化,添加注解
spring.xml
1.开启注解扫描
<context:component-scan base-package="com.baizhi"/>
2.创建数据源对象
<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/test?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
3.创建sqlsessionFactory
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入dataSource mapperlocation 别名-->
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:com/baizhi/mapper/*.xml"/>
<property name="typeAliasesPackage" value="com.baizhi.entity"/>
</bean>
4.创建Dao对象
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.baizhi.dao"/>
</bean>
5.创建事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
6.开启注解式事务生效
<tx:annotation-driven transaction-manager="transactionManager"/>
11.spring当中的注释
1.实例化相关注解
# 1. @Component(value="beanid")
修饰范围: 用在类上
注解作用: 通用的创建实例的注解,用来创建当前这个类的实例
value属性: 用来指定创建的对象在工厂中的唯一标识 如果不指定默认创建对象在工厂中的标识为类名首字母小写
# 2. @Repository
修饰范围: 用在类上
注解作用: @component的子类注解专用于DAO组件的创建,通常加在DAO组件上
value属性: 用来指定创建的对象在工厂中的唯一标识 如果不指定默认创建对象在工厂中的标识为类名首字母小写
# 3. @Service
修饰范围: 用在类上
注解作用: @component的子类注解专用于Service组件的创建,通常加在Service组件上
value属性: 用来指定创建的对象在工厂中的唯一标识 如果不指定默认创建对象在工厂中的标识为类名首字母小写
# 4. @Controller
修饰范围: 用在类上
注解作用: @component的子类注解专用于Action组件的创建,通常加在Action组件上
value属性: 用来指定创建的对象在工厂中的唯一标识 如果不指定默认创建对象在工厂中的标识为类名首字母小写
2.控制对象的创建次数的注解
# 1. @Scope(value="singleton|prototype")
修饰范围: 用在类上
注解作用: 用来控制这个实例在工厂中的创建次数
value属性: singleton为单例,prototype为多例 默认单例
3.注入相关的注解
# 1. @Autowired(Spring提供)
修饰范围: 用在成员变量或成员变量的GET/SET方法上
注解作用: 用来给类中成员变量赋值
注入原则: 默认根据类型自动注入
# 2. @Resource(JAVAEE提供)
修饰范围: 用在成员变量或成员变量的GET/SET方法上
注解作用: 用来给类中成员变量赋值
注入原则: 默认根据名称自动注入名称找不到根据类型自动注入
4.控制事务的相关注解
# 1. @Transactional
修饰范围: 用在类上主要用在业务层组件类上或者是方法上
注解作用: 用来给类中方法加入事务,当类上和方法上同时存在该注解时局部优先
注解属性:
propagation 用来控制传播属性
Isolation 用来控制隔离级别
timeout 用来设置超时性
rollback-for 用来设置什么异常回滚
norollback-for 用来设置什么异常不会滚
readonly 用来设置事务读写性