Spring整合MyBatis
步骤:
-
导入相关jar包
- junit
- mybatis
- mysql
- spring相关
- aop织入
- mybatis-spring
pom.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.example</groupId> <artifactId>Spring-Study</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>spring-10-mybatis</artifactId> <dependencies> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.10.0</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.13</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>6.0.11</version> </dependency> <!--SpringJDBC--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.12</version> </dependency> <!--AOP织入包--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> </dependency> <!--Mybatis 和 Spring 整合--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.6</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.28</version> </dependency> </dependencies> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> </project>
-
编写配置文件
-
测试
回顾MyBatis
数据库还用我们之前使用过的mybatis库
-
编写实体类
实体类照着表写就好了
package xyz.luck1y.pojo; import lombok.Data; @Data public class User { private int id; private String name; private String pwd; }
这里偷懒用了Lombok,要导入包
-
编写核心配置文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.example</groupId> <artifactId>Spring-Study</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>spring-10-mybatis</artifactId> <dependencies> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.10.0</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.13</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>6.0.11</version> </dependency> <!--SpringJDBC--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.12</version> </dependency> <!--AOP织入包--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> </dependency> <!--Mybatis 和 Spring 整合--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.6</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.28</version> </dependency> </dependencies> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build> </project>
-
编写mybatis-config配置文件
<?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!--开启驼峰命名--> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <typeAliases> <package name="xyz.luck1y.pojo"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper class="xyz.luck1y.mapper.UserMapper"/> </mappers> </configuration>
-
编写接口
package xyz.luck1y.mapper; import xyz.luck1y.pojo.User; import java.util.List; public interface UserMapper { List<User> selectUser(); }
-
编写Mapper.xml
<?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="xyz.luck1y.mapper.UserMapper"> <select id="selectUser" resultType="user"> select * from mybatis.user </select> </mapper>
-
测试
import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.jupiter.api.Test; import xyz.luck1y.mapper.UserMapper; import xyz.luck1y.pojo.User; import java.io.IOException; import java.io.InputStream; import java.util.List; public class MyTest { @Test public void test() throws IOException { String resources = "mybatis-config.xml"; InputStream in = Resources.getResourceAsStream(resources); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in); SqlSession sqlSession = sessionFactory.openSession(true); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> users = mapper.selectUser(); for (User user : users) { System.out.println(user); } sqlSession.close(); } }
MyBatis-Spring 整合方式一
MyBatis-Spring
官网:mybatis-spring –
MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和
SqlSession
并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的DataAccessException
。 最终,可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。要使用 MyBatis-Spring 模块,只需要在类路径下包含
mybatis-spring-2.0.6.jar
文件和相关依赖即可。要使用 MyBatis-Spring 模块,只需要在类路径下包含
mybatis-spring-3.0.2.jar
文件和相关依赖即可。如果使用 Maven 作为构建工具,仅需要在 pom.xml 中加入以下代码即可:
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.2</version> </dependency>
-
编写数据源配置(此配置基本替代了原来mybatis-config配置文件)
spring-dao.xml:
<?xml version="1.0" encoding="UTF8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--DataSource:使用Spring的数据源替换MyBatis的配置 c3p0 dbcp --> <!--我们这里使用Spring提供的JDBC,可以将MyBatis配置文件中的 <environments> 部分去掉了--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean> <!--sqlSessionFactory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!--绑定 MyBatis 配置文件(可选)--> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:xyz/luck1y/mapper/*.xml"/> </bean> <!--SqlSessionTemplate:就是我们要使用的sqlSession--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!--只能使用构造器注入方法注入,因为它没有set方法--> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean> <!--此处可以提取出来新建一个单独的Spring配置--> <bean id="userMapper" class="xyz.luck1y.mapper.UserMapperImpl"> <property name="sqlSession" ref="sqlSession"/> </bean> </beans>
-
给接口添加实现类(可选)
package xyz.luck1y.mapper; import org.mybatis.spring.SqlSessionTemplate; import xyz.luck1y.pojo.User; import java.util.List; public class UserMapperImpl implements UserMapper { // 我们原来的所有操作都使用sqlSession来执行,现在都使用sqlSessionTemplate private SqlSessionTemplate sqlSession; public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } @Override public List<User> selectUser() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.selectUser(); } }
-
注入实现类到Spring容器中,新建一个Spring配置,专门用来处理除Mybatis配置外的配置(可选)
applicationContext.xml:
<?xml version="1.0" encoding="UTF8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <import resource="spring-dao.xml"/> <bean id="userMapper" class="xyz.luck1y.mapper.UserMapperImpl"> <property name="sqlSession" ref="sqlSession"/> </bean> </beans>
-
测试
第一种没单独写applicationContext.xml配置文件的
@Test public void test() throws IOException { ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); for (User user : userMapper.selectUser()) { System.out.println(user); } }
第二种:注入实现类
@Test public void test() throws IOException { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); for (User user : userMapper.selectUser()) { System.out.println(user); } }
-
结果:
MyBatis-Spring 整合方式二
方式一中国我们需要在xml中注册以下内容:
<!--SqlSessionTemplate:就是我们要使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用构造器注入方法注入,因为它没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
方式二就不用注册这个SqlSessionTemplate
,直接在实现类中继承一个类:SqlSessionDaoSupport
package xyz.luck1y.mapper;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import xyz.luck1y.pojo.User;
import java.util.List;
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
@Override
public List<User> selectUser() {
return getSqlSession().getMapper(UserMapper.class).selectUser();
}
}
进入SqlSessionDaoSupport
类,可以看到这个类就是把方式一的内容封装了一下,因此,我们就不用再xml中注册sqlSessionTemplate
了
将这个实现类注册到容器中,只需要将spring-dao.xml中配置的sqlSessionFactory注入即可:
<bean id="userMapper2" class="xyz.luck1y.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
使用方式二,相当于将中间的一步省略掉了,其实是被SqlSessionDaoSupport
封装起来了。
声明式事务
事务回顾
- 把一组业务当成一个业务来做,要么都成功,要么都失败!
- 事务在项目开发中,十分重要,涉及到数据的一致性问题。
- 确保完整性和一致性
- 事物的ACID原则:
- 原子性、一致性、隔离性、持久性
Spring中的事务管理
一个使用 MyBatis-Spring 的其中一个主要原因是它允许 MyBatis 参与到 Spring 的事务管理中。而不是给 MyBatis 创建一个新的专用事务管理器,MyBatis-Spring 借助了 Spring 中的
DataSourceTransactionManager
来实现事务管理。一旦配置好了 Spring 的事务管理器,你就可以在 Spring 中按你平时的方式来配置事务。并且支持
@Transactional
注解和 AOP 风格的配置。在事务处理期间,一个单独的SqlSession
对象将会被创建和使用。当事务完成时,这个 session 会以合适的方式提交或回滚。事务配置好了以后,MyBatis-Spring 将会透明地管理事务。这样在你的 DAO 类中就不需要额外的代码了。
在Spring中的事务管理,分为以下两类:
- 声明式事务:AOP
- 编程式事务:在代码中进行事务的管理
我们主要学习声明式事务:因为它在不改变原有代码的基础上,使用AOP的方法完成了事务的声明。
在Spring的配置文件中,配置声明式事务
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--结合AOP实现事务的织入-->
<!--配置事物通知:-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给哪些方法配置事务-->
<!--配置事务的传播特性 propagation= -->
<tx:attributes>
<!-- <tx:method name="add" propagation="REQUIRED"/>-->
<!-- <tx:method name="delete" propagation="REQUIRED"/>-->
<!-- <tx:method name="update" propagation="REQUIRED"/>-->
<!-- <tx:method name="query" read-only="true"/>-->
<!--所有的都支持-->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* xyz.luck1y.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
接口:
package xyz.luck1y.mapper;
import xyz.luck1y.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> selectUser();
// 添加一个用户
public int addUser(User user);
// 删除一个用户
public int deleteUser(@Param("id") int id);
}
mapper.xml
注意:这里我们故意写错了一条语句,用来测试事务
deletes from mybatis.user where id=#{id}
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xyz.luck1y.mapper.UserMapper">
<select id="selectUser" resultType="user">
select * from mybatis.user
</select>
<insert id="addUser" parameterType="user">
insert into mybatis.user (id, name, pwd) VALUES (#{id}, #{name}, #{pwd})
</insert>
<delete id="deleteUser" parameterType="int">
<!--故意写错,测试事务-->
deletes from mybatis.user where id=#{id}
</delete>
</mapper>
实现类:
package xyz.luck1y.mapper;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import xyz.luck1y.pojo.User;
import java.util.List;
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {
@Override
public List<User> selectUser() {
User user = new User(8, "小王", "1234141");
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
mapper.addUser(user);
mapper.deleteUser(8);
return mapper.selectUser();
}
@Override
public int addUser(User user) {
return getSqlSession().getMapper(UserMapper.class).addUser(user);
}
@Override
public int deleteUser(int id) {
return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
}
}
测试类:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import xyz.luck1y.mapper.UserMapper;
import xyz.luck1y.pojo.User;
import java.util.List;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
List<User> users = userMapper.selectUser();
for (User user : users) {
System.out.println(user);
}
}
}
初始表:
关闭事务,执行测试程序:可以插入成功,并且删除也成功
开启事务,还原表状态,执行测试程序,表的内容并没有变化:
说明事务开启后,两个语句一起都失效了,即一条错误语句导致所有语句都失效,将错误语句改正,并且为了看到结果,增加8号,删除7号,测试:
即如果我们没有开启事务,那么插入新用户8号会执行成功,如果我们开启了事务,那么插入和删除都不会成功。
综上所述:
如果不配置事务,会存在数据提交不一致的情况,后果很严重~
事务在项目的开发中十分重要,涉及到数据的一致性和完整性问题。
另外,如果我们不在Spring中配置声明式事务的话,就需要在代码中进行编程式事务的配置。