Spring整合Mybatis
一. 简单实现Mybatis
-
导入相关依赖(pom.xml)
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency>
-
编写实体类
package com.wtw.pojo; import lombok.Data; @Data //lombok注解,实现set和get方法 public class User { private int id; private String userName; private String password; }
-
编写UserDao接口
package com.wtw.dao; import com.wtw.pojo.User; import java.util.List; public interface UserMapper { public List<User> selectUser();//简单的俩个方法接口,查询所有用户和按id查询 public User selectUserById(); }
-
编写接口对应的Mapper映射文件(UserMapper.xml)
<?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"> <mapper namespace="com.wtw.dao.UserMapper"> <select id="selectUser" resultType="User"> select * from user </select> <select id="selectUserById" resultType="User"> select * from user where id=1 </select> </mapper>
注意此文件内不能有中文注释,否则运行报错:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [spring-dao.xml]: Invocation of init method failed; nested exception is org.springframework.core.NestedIOException: Failed to parse mapping resource: 'file [D:\Desktop\spring-transaction\target\classes\com\wtw\dao\mapper\UserMapper.xml]'; nested exception is org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: 1 字节的 UTF-8 序列的字节 1 无效。
目前没找到解决方法,有待解决???
-
编写mybatis配置文件(mybatis-config.xml),resource目录下,默认为classpath
<?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> <typeAliases> <package name="com.wtw.pojo"/> </typeAliases> <!--后面在beans.xml中做了,这里需要先打开注释-> <!--配置数据库环境-> <!- <environments default="development">--> <!-- <environment id="development">--> <!-- <transactionManager type="JDBC"/>--> <!-- <dataSource type="POOLED">--> <!-- <property name="driver" value="com.mysql.jdbc.Driver"/>--> <!-- <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/>--> <!-- <property name="username" value="root"/>--> <!-- <property name="password" value="4321"/>--> <!-- </dataSource>--> <!-- </environment>--> <!-- </environments>--> <!--配置mapper.xml映射文件的路径-> <!-- <mappers>--> <!-- <package name="com.wtw.dao"/>--> <!-- </mappers>--> </configuration>
-
编写测试类进行测试
import com.wtw.dao.UserMapper; import com.wtw.pojo.User; 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.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class Test1 { @Test public void selectUser() { String resource = "mybatis-config.xml"; InputStream inputStream= null; try { inputStream = Resources.getResourceAsStream(resource);//注意此处的Resource类要导对包apache下的 } catch (IOException e) { e.printStackTrace(); }//读取mybatis配置文件 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession();//通过SqlSessionFactory新建sqlSession UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userList = mapper.selectUser(); for (User user:userList) { System.out.println(user); } sqlSession.close();//开启资源都要记得关闭 } }
-
运行上面的测试类,发现报错,需要配置Maven静态资源过滤问题(pom.xml)
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
数据库名:mybatis
表名:user 字段:id int,username String ,password String
二. Spring整合mybatis(MyBatis-Spring)
-
导入依赖
<!--spring相关--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.10.RELEASE</version> </dependency> <!--aspectJ AOP 织入器--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> <!--mybatis-spring整合包--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.2</version> </dependency>
-
编写Spring配置文件beans.xml模板,以后可以直接复制使用
<?xml version="1.0" encoding="UTF-8"?> <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"> </beans>
-
在beans.xml中配置数据源,取代mybatis-config.xml中的配置
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="xxxx"/> </bean>
-
在beans.xml中配置SqlSessionFactory,与Mybatis关联
<!-- 配置SqlSessionFactory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!-- 关联Mybatis配置文件及mapper.xml--> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:com/wtw/dao/*.xml"/> </bean>
-
在beans.xml中注册sqlSessionTemplate , 关联sqlSessionFactory,sqlSessionTemplate等同于SqlSession,Spring帮忙封装了
<!--注册sqlSessionTemplate , 关联sqlSessionFactory--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!--利用构造器注入,这里只能用构造器注入,因为SqlSessionFactoryBean类中只有构造方法,没有定义set方法--> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean>
-
编写UserDao接口的实现类,从而使用sqlSessionTemplate
package com.wtw.dao; import com.wtw.pojo.User; import org.mybatis.spring.SqlSessionTemplate; import java.util.List; public class UserDaoImpl implements UserMapper { //使用sqlSession时不用我们自己new,IOC交由Spring管理,所以这里必须有set方法。记得去beans.xml中去注册bean private SqlSessionTemplate sqlSession; public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } public List<User> selectUser() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.selectUser(); } } <bean id="userDao" class="com.wtw.dao.UserDaoImpl"> <property name="sqlSession" ref="sqlSession"/> </bean>
-
编写测试类,测试
import com.wtw.dao.UserMapper; import com.wtw.pojo.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.List; public class Test2 { @Test public void test2(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserMapper mapper = context.getBean("userDao", UserMapper.class); List<User> userList = mapper.selectUser(); for (User user:userList) { System.out.println(user); } } }
三. 实现方式二
1.2.3.4.步同上
第五步 不需要再去管理SqlSessionTemplate,即不需要去注册sqlSessionTemplate,实现UserDao接口时,去继承SqlSessionDaoSupport类,
package com.wtw.dao; import com.wtw.pojo.User; import org.mybatis.spring.support.SqlSessionDaoSupport; import java.util.List; //方式二 继承SqlSessionDaoSupport 省去了new sqlSession,直接利用 getSqlSession() 获得 , 然后直接注入SqlSessionFactory public class UserDao2Impl extends SqlSessionDaoSupport implements UserMapper { public List<User> selectUser() { return getSqlSession().getMapper(UserMapper.class).selectUser(); } public User selectUserById() { return getSqlSession().getMapper(UserMapper.class).selectUserById(); } }
这里还需要修改beans.xml文件的配置
<bean id="userDao" class="com.wtw.dao.UserDao2Impl"> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean>
测试:
import com.wtw.dao.UserMapper; import com.wtw.pojo.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.List; public class Test3 { @Test public void test3(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans2.xml"); UserMapper mapper= context.getBean("userDao", UserMapper.class); List<User> userList = mapper.selectUser(); for (User user:userList) { System.out.println(user); } System.out.println(mapper.selectUserById()); } }
四. 声明式事务
事务:用来保证应用数据的一致性和完整性。
四大原则:ACID
-
原子性(atomicity)
-
一系列的操作是一个整体,要么全部执行,要么全部不执行。
-
一致性(consistency)
-
实时提交,只要有操作产生,事务就被提交,数据在资源中永远被更新。
-
隔离性(isolation)
-
多个事务处理同一数据,相互隔离,不会互相影响。
-
持久性(durability)
事务一旦提交,无论系统出现什么问题,数据都不会被影响,结果被持久化在了数据库这样的存储器上。
四大原则的作用就是保证一系列的操作要么全部成功,要么全部失败,终极目的就是保证应用数据的一致性和完整性。
Spring中的事务管理
支持编程式事务管理和声明式的事务管理
编程式事务管理
- 将事务管理代码嵌到业务方法中来控制事务的提交和回滚
- 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
声明式事务管理
- 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
- 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。
实现步骤:
1.beans.xml文件配置约束头
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
2.在beans.xml中注册事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
3.配置事务的通知
<!--配置事务通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--配置哪些方法使用事务,*为全部方法,配置事务的传播特性,默认REQUIRED--> <tx:method name="*" propagation="REQUIRED"/> <!-- <tx:method name="selectUser" propagation="REQUIRED"/>--> <!-- <tx:method name="deleteUser" propagation="REQUIRED"/>--> <!-- <tx:method name="insertUser" propagation="REQUIRED"/>--> </tx:attributes> </tx:advice>
4.配置AOP,说明在哪里织入事务
<!--配置aop织入事务--> <aop:config> <aop:pointcut id="txPointcut" expression="execution(* com.wtw.dao.impl.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> </aop:config>
事务传播性详解:
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。
spring支持7种事务传播行为:
-
propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择,默认。
-
propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
-
propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
-
propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
-
propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
-
propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
-
propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作
-