3. Spring整合Mybatis编程DAO层开发
1. 项目引入相关依赖
spring mybatis mysql mybatis-spring druid
2. 编写spring.xml
整合:spring 接管 mybatis 中 SqlSessionFactory对象的创建
<!--创建DataSource-->
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/lb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--创建sqlSessionFactory-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<!--依赖数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
3. 建表
4. 实体类
5. DAO接口
public interface UserDAO {
List<User> findAll();
}
6. 开发Mapper
<mapper namespace="com.baizhi.dao.UserDAO">
<select id="findAdd" resultType="com.baizhi.eneity.User">
select id, name, age, bir from t_user
</select>
</mapper>
注意:开发完mapper文件后一定要在spring.xml中注册
<!--创建sqlSessionFactory-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<!--依赖数据源-->
<property name="dataSource" ref="dataSource"/>
<!--注册mapper配置文件-->
<property name="mapperLocations">
<array>
<value>classpath:com/baizhi/mapper/UserDAOMapper.xml</value>
</array>
</property>
</bean>
7. 启动工厂获取SqlSessionFactory
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) context.getBean("sqlSessionFactory");
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDAO userDAO = sqlSession.getMapper(UserDAO.class);
userDAO.findAll().forEach(user -> {System.out.println(user);});
再进一步可以直接在工厂中注册SqlSessionFactory、注册DAO组件类,
并且在DAO组件里面注入SqlSessionFactory和DAO接口的类型,这样就可以使用spring工厂直接获取UserDAO组件类了
不用再获取SqlSessionFactory了
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserDAO userDAO = (UserDAO) context.getBean("userDAO");
接下来我们来整合mybatis和spring并一步一步的开发DAO层:
首先,我们新建一个模块,使用标准的包结构
之后我们要在pom.xml文件中引入依赖
spring mybatis mysql mybatis-spring druid
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>
在数据库中建表
创建实体类
public class User {
private String id;
private String name;
private Integer age;
private Date bir;
public User() {
}
public User(String id, String name, Integer age, Date bir) {
this.id = id;
this.name = name;
this.age = age;
this.bir = bir;
}
}
创建DAO接口
public interface UserDAO {
List<User> findAll();
}
写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">
<mapper namespace="com.baizhi.dao.UserDAO">
<select id="findAll" resultType="com.baizhi.eneity.User">
select id, name, age, bir from t_user
</select>
</mapper>
编写spring.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">
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/lb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations">
<array>
<value>classpath:com/baizhi/mapper/UserDAOMapper.xml</value>
</array>
</property>
</bean>
</beans>
测试和结果
最后我们来说一个优化
对于我们来说,我们不关心SqlSessionFactory如何获取SqlSession的,也不关心SqlSession如何获取获取DAO接口的,我们关心能否一步就获得想要的DAO接口呢,这是可以的,我们先在工厂中注册SqlSessionFactory对象,因为SqlSessionFactory可以获取SqlSession对象,然后传入DAO接口类型就获得了DAO接口对象;然后我们可以在工厂中创建一个DAO组件类,注入SqlSessionFactory对象和DAO接口类型就可以直接获得DAO对象了,这个类就是mybatis-spring包中的MapperFactoryBean类
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/lb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations">
<array>
<value>classpath:com/baizhi/mapper/UserDAOMapper.xml</value>
</array>
</property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperFactoryBean" name="userDAO">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
<property name="mapperInterface" value="com.baizhi.dao.UserDAO"/>
</bean>
public class TestUserDAO {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserDAO userDAO = (UserDAO) context.getBean("userDAO");
userDAO.findAll().forEach(user -> System.out.println("user = " + user));
}
}
总结:
4. Spring整合Mybatis编程Service层开发
# spring、mybatis整合Service层开发时如何加入事务控制
1. Mybatis框架中事务控制
SqlSession 提交:sqlSession.commit(); 回滚:sqlSession.rollback()
// 无论用的是哪个简化数据库的框架,它的底层一定是jdbc,sqlSession底层调的也是Connection的commit()、rollback()
Mybatis 是对 原始jdbc技术的封装 ===> Connection(数据库其实只认java.sql.Connection commit() | rollback())
项目中真正负责数据库事务控制的对象:Connection 对象
2. 用来实现事务控制的核心对象是
Connection 连接对象的 commit() rollback()
3. 如何在现有的项目中获取Connection对象
注意:在现有项目中DruidDataSource是一个连接池 在连接池里面装的就是一个一个的Connection连接
Connection conn = DruidDataSource.getConnection();
4. 给现有业务层加入事务
UserServiceImpl
private DataSource dataSource; // 提供公开的set方法
save(){
try{
// 控制事务
druidDataSource.getConnection().setAutoCommit(false) // 将事务提交方式改为手动
// 处理业务
// 调用DAO
druidDataSource.getConnection().commit();
}catch(...){
druidDataSource.getConnection().rollback();
}
}
连接控制事务得保证是同一个连接对象,在业务层拿到的连接对象得和DAO真正执行时打开的数据库连接对象保持一致
DAO真正执行是由框架内部的jar包创建出来的,不受控制,与业务层拿到的连接不是同一个,所以利用上面的代码控制
事务是不行的
4. 在Spring和Mybatis框架中提供了一个类
DataSourceTransactionManager 数据源事务管理器
作用
1. 在全局创建一个事务管理器,用来统一调度 业务层当前线程使用的连接对象和DAO层使用的连接对象一致
由它来决定哪个线程在执行业务层时用的是这个连接,在执行DAO时同样用这个连接
创建
<!--数据源管理器-->
<!--它是用来控制数据源的线程安全问题,它不生产数据源,所以要告诉它控制哪个数据源的线程安全问题,所以要注入数据源-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<!--注入数据源对象-->
<property name="dataSource" ref="dataSource"/>
</bean>
5. 给现有的业务层加入事务控制
public class UserServiceImpl implements UserService{
private UserDAO userDAO;
private PlatformTransactionManager transactionManager; //setTransactionManager方法
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
@Override
public void save(User user) {
try{
// 创建事务配置对象
// 接口,后面new的用实现类
TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
// 获取事务状态
//传入事务配置
TransactionStatus status = platformTransactionManager.getTransaction(transactionDefinition);
//
try {
// 控制事务
// 处理业务
userDAO.save(user);
int i = 1 / 0;
// 需要传入事务状态
platformTransactionManager.commit(status);
} catch (Exception e) {
e.printStackTrace();
platformTransactionManager.rollback(status);
}
}
}
在具体讲解Spring整合Mybatis编程Service层开发之前,我们先来补充一个小的知识点
-
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.baizhi.dao"/>
</bean>
- 使用MapperScannerConfigurer,一次性创建包中所有的接口
-
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations">
<array>
<value>classpath:com/baizhi/mapper/UserDAOMapper.xml</value>
</array>
</property>
<property name="typeAliasesPackage" value="com.baizhi.eneity"/>
</bean>
- typeAliasesPackage:用来给指定包中所有类起别名 默认的别名:类名|类名首字母小写
之后我们正式进入Spring整合Mybatis编程Service层开发
因为在前面开发DAO层时已经在pom.xml中导入依赖了,所以在开发Service时就不需要再导入依赖了,我们直接开发Service接口
public interface UserService {
List<User> findAll();
void save(User user);
}
这里我们先不管事务操作,创建UserService接口的实现类,UserService的实现类里面有一个userDAO接口对象
package com.baizhi.service;
import com.baizhi.dao.UserDAO;
import com.baizhi.eneity.User;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import java.util.List;
import java.util.UUID;
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);
}
}
编写spring.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">
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/lb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations">
<array>
<value>classpath:com/baizhi/mapper/UserDAOMapper.xml</value>
</array>
</property>
<property name="typeAliasesPackage" value="com.baizhi.eneity"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.baizhi.dao"/>
</bean>
<bean class="com.baizhi.service.UserServiceImpl" name="userService">
<property name="userDAO" ref="userDAO"/>
</bean>
</beans>
测试和结果
测试之前t_user表中记录:
运行代码:
运行之后t_user表中记录:
上面表记录说明执行成功了。
接下来我们尝试使用事务进行管理
我们先看一下是否有事务自动提交
为什么有异常却仍然插入了数据呢,这时因为userDAO 方法上有一个小事务,仅限于DAO的方法,DAO的方法结束后会做一个提交,这个小事务仅是为了方便测试DAO, 当外部(Service方法内)存在事务时,小事务(仅限于DAO的方法中的事务)自动消失(小事务不生效)。所以我们就需要手动进行管理了,我们知道,无论什么框架与数据库打交道时,底层都是Connection对象与数据库打交道,所以我们尝试用Connection进行事务管理,但是这确实不行的,因为Connection管理事务的前提是相同的Connection对象,当调用userDAO管理事务的Connection对象和userService管理事务的Connection对象不是同一个,那怎么办呢?官方提供了事务管理器类platformTransactionManager,它是用来控制数据源的线程安全问题,它不生产数据源,我们把它声明为成员变量,并声明公开的set方法,让spring工厂管理,所以UserServiceImpl实现类代码如下:
UserServiceImpl实现类
public class UserServiceImpl implements UserService{
private UserDAO userDAO;
private PlatformTransactionManager platformTransactionManager;
public void setPlatformTransactionManager(PlatformTransactionManager platformTransactionManager) {
this.platformTransactionManager = platformTransactionManager;
}
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 = platformTransactionManager.getTransaction(transactionDefinition);
try {
userDAO.save(user);
int i = 1 / 0;
platformTransactionManager.commit(status);
} catch (Exception e) {
e.printStackTrace();
platformTransactionManager.rollback(status);
}
}
}
mapper配置文件
<?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">
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/lb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations">
<array>
<value>classpath:com/baizhi/mapper/UserDAOMapper.xml</value>
</array>
</property>
<property name="typeAliasesPackage" value="com.baizhi.eneity"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.baizhi.dao"/>
</bean>
<bean class="com.baizhi.service.UserServiceImpl" name="userService">
<property name="userDAO" ref="userDAO"/>
<property name="platformTransactionManager" ref="transactionManager"/>
</bean>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
测试和结果
测试之前的表
测试:
测试之后的表:
上述结果说明我们成功的使用事务管理了Service层。
总结:
|