spring复习05,spring整合mybatis,声明式事务
- spring整合mybatis
- 1. 在pom.xml中导入依赖
- 2. 创建实体类
- 3. 创建Mapper接口
- 4. 配置mybatis核心配置文件
- 5. 编写映射文件Mapper.xml
- 6. 编写数据源配置
- 7. sqlSessionFactory
- 8. sqlSessionTemplate
- 9. 需要给接口加实现类
- 10. 将实现类注入到spring中
- 11. 添加声明式事务
- 12. 测试使用
- 声明式事务
- 1. 传播行为
- 2. 隔离级别
- 3. 只读提示 readOnly
- 4. 事务超时期间
spring整合mybatis
新建一个maven项目,对用户的增删改查的业务操作。
1. 在pom.xml中导入依赖
<!-- 基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.1</version>
</dependency>
<!-- Spring 持久化层支持jar包 -->
<!-- Spring 在执行持久化层操作、与持久化层技术进行整合过程中,需要使用orm、jdbc、tx三个
jar包 -->
<!-- 导入 orm 包就可以通过 Maven 的依赖传递性把其他两个也导入 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.1</version>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!--mybatis核心-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<!-- 数据源 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.0</version>
</dependency>
<!-- spring-aspects会帮我们传递过来aspectjweaver -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.1</version>
</dependency>
这里我的数据源选择的是mybatis-spring。链接: mybatis-spring介绍和快速入门
2. 创建实体类
package com.gothic.sunset.pojo;
public class User {
private Integer id;
private String userName;
private String password;
public User() {
}
public User(Integer id, String userName, String password) {
this.id = id;
this.userName = userName;
this.password = password;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
3. 创建Mapper接口
package com.gothic.sunset.mapper;
import com.gothic.sunset.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserMapper {
public int addUser(User user);
public int updateUser(@Param("id") int id);
public int delete(@Param("id") int id);
public List<User> selectAllUsers();
}
4. 配置mybatis核心配置文件
mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--MyBatis核心配置文件的标签必须按照指定的顺序去配置
properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,
objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?
-->
<settings>
<!--将下划线映射为驼峰-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<!--包的别名-->
<package name="com.gothic.sunset"/>
</typeAliases>
</configuration>
5. 编写映射文件Mapper.xml
UserMapper.xml(在resources下的com/gothic/sunset/mapper目录下):
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace需要填写对应的mapper接口来绑定-->
<mapper namespace="com.gothic.sunset.mapper.UserMapper">
<!--public int addUser(User user);-->
<insert id="addUser" >
insert into user(id,user_name,password) values (#{id},#{userName},#{password})
</insert>
<!-- public int updateUser(@Param("id") int id); -->
<update id="updateUser" >
update user
set user_name=#{userName},
password = #{password}
where id = #{id}
</update>
<!-- public int delete(@Param("id") int id);-->
<delete id="delete" >
delete from user where id =#{id}
</delete>
<!--public List<User> selectAllUsers();-->
<select id="selectAllUsers" resultType="User">
select id,user_name,password from user where id =#{id}
</select>
</mapper>
6. 编写数据源配置
在这里我的数据库连接配置信息在另一个文件中jdbc.properties中,通过 <context:property-placeholder location="classpath:jdbc.properties"/>
引入。
jdbc.properties:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8
jdbc.username=root
jdbc.password=root
在resources目录下新建spring-dao.xml:
<!--引入jdbc.properties-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
7. sqlSessionFactory
也在spring-dao.xml中编写:
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--绑定mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--绑定mapper映射文件-->
<property name="mapperLocations" value="classpath:com/gothic/sunset/mapper/*.xml"/>
</bean>
在这里可以通过sqlSessionFactory来绑定mapper映射文件,也可以像之前一样在mybatis-config.xml中mappers标签
来绑定mapper映射文件。
8. sqlSessionTemplate
在spring-dao.xml中编写:
使用 SqlSessionFactory 作为构造方法的参数来创建 SqlSessionTemplate 对象。
<!--配置sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
SqlSessionTemplate 是 MyBatis-Spring 的核心。作为 SqlSession 的一个实现,可以使用它无缝代替你代码中已经在使用的 SqlSession。 SqlSessionTemplate 是线程安全的,可以被多个 DAO 或映射器所共享使用。
Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作。(本着万物皆bean,交由容器处理)
9. 需要给接口加实现类
因为现在我们的sqlsession已经交由ioc容器来管理,所以我们可以通过接口实现类的方式,直接使用依赖注入去完成功能,这会使我们的代码更简单。
package com.gothic.sunset.mapper;
import com.gothic.sunset.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper{
//set注入sqlSession对象
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public int addUser(User user) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int i = mapper.addUser(user);
return i;
}
@Override
public int updateUser(int id) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.updateUser(id);
}
@Override
public int delete(int id) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.delete(id);
}
@Override
public List<User> selectAllUsers() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectAllUsers();
}
}
这里的sqlSession也可以通过注解的方式注入,这样子就更简单了。
10. 将实现类注入到spring中
在applicationContext.xml中编写:
<!--导入spring-dao.xml-->
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.gothic.sunset.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
11. 添加声明式事务
要开启 Spring 的事务处理功能,在 Spring 的配置文件中创建一个 DataSourceTransactionManager 对象。
事务管理器:
<!--
开启事务的注解驱动
通过注解@Transactional所标识的方法或标识的类中所有的方法,都会被事务管理器管理事务
-->
<!-- transaction-manager属性的默认值是transactionManager,如果事务管理器bean的id正好就
是这个默认值,则可以省略这个属性 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
这里如果使用@Transactional注解方式来配置的话,配置事务通知就需要使用<tx:annotation-driven transaction-manager="transactionManager" />
。
配置事务通知:
<!-- tx:advice标签:配置事务通知 -->
<!-- id属性:给事务通知标签设置唯一标识,便于引用 -->
<!-- transaction-manager属性:关联事务管理器 -->
<tx:advice transaction-manager="transactionManager" id="txAdvice">
<tx:attributes>
<!-- tx:method标签:配置具体的事务方法 -->
<!-- name属性:指定方法名,也可以使用星号代表多个字符 -->
<tx:method name="addUser" propagation="REQUIRED"/>
<tx:method name="updateUser" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="selectAllUsers" read-only="false"/>
</tx:attributes>
</tx:advice>
read-only属性:设置只读属性
rollback-for属性:设置回滚的异常
no-rollback-for属性:设置不回滚的异常
isolation属性:设置事务的隔离级别
timeout属性:设置事务的超时属性
propagation属性:设置事务的传播行为
配置aop事务切入:
<!--配置事务切入-->
<aop:config>
<!--横切点-->
<aop:pointcut id="pointCut" expression="execution(* com.gothic.sunset.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"/>
</aop:config>
12. 测试使用
@Test
public void testJdbc(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = ioc.getBean("userMapper", UserMapper.class);
User user1 = new User(1, "一叶知秋", "110244001");
User user2 = new User(2, "大漠孤烟", "110244003");
User user3 = new User(3, "夜雨声烦", "110244023");
User user4 = new User(4, "树藤海岛", "110244026");
userMapper.addUser(user1);
userMapper.addUser(user2);
userMapper.addUser(user3);
userMapper.addUser(user4);
}
观察我们的测试代码,越来越简单,相比于之前sqlSessionFactory的工具类也更简单了。
插入成功:
声明式事务
声明式事务(declarative transaction management)是Spring提供的对程序事务管理的方式之一。
Spring使用AOP来完成声明式的事务管理,因而声明式事务是以方法为单位,在Spring中事务属性有以下四个参数:
1. 传播行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。
2. 隔离级别
数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别。SQL标准中规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。
隔离级别一共有四种:
- 读未提交:READ UNCOMMITTED
允许Transaction01读取Transaction02未提交的修改。 - 读已提交:READ COMMITTED、
要求Transaction01只能读取Transaction02已提交的修改。 - 可重复读:REPEATABLE READ
确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。 - 串行化:SERIALIZABLE
确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。
3. 只读提示 readOnly
对一个查询操作来说,如果我们把它设置成只读,就能够明确告诉数据库,这个操作不涉及写操作。这样数据库就能够针对查询操作来进行优化。
4. 事务超时期间
事务在执行过程中,有可能因为遇到某些问题,导致程序卡住,从而长时间占用数据库资源。而长时间占用资源,大概率是因为程序运行出现了问题(可能是Java程序或MySQL数据库或网络连接等等)。此时这个很可能出问题的程序应该被回滚,撤销它已做的操作,事务结束,把资源让出来,让其他正常程序可以执行。
超时回滚,释放资源
以上的四个属性在xml和注解中都可以配置:
xml中:
<tx:method name="xxx"
propagation="REQUIRED|.."
read-only="true|false"
isolation="DEFAULT|READ_UNCOMMITTED|READ_COMMITTED|REPEATABLE_READ|SERIALIZABLE"
rollback-for="..."
timeout="..."/>
好多我就不一一列出,大家可以自行查看文档。
注解:
@Transactional(isolation = "",timeout = "",
readOnly = true|flase,propagation = "",rollbackFor...)
声明式事务默认只针对运行时异常回滚,编译时异常不回滚。可以通过@Transactional中相关属性设置回滚策略。
rollbackFor属性:需要设置一个Class类型的对象
rollbackForClassName属性:需要设置一个字符串类型的全类名
noRollbackFor属性:需要设置一个Class类型的对象
rollbackFor属性:需要设置一个字符串类型的全类名
spring大概的过了一遍,过几天要开始springMvc的复习了,果然“配置地狱”!!!