一、Spring对MyBatis的整合
①首先在pom.xml中添加所需要的依赖:
<dependencies>
<!--测试包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--spring依赖的包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>5.2.7.RELEASE</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<!--aop所依赖的包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<!--mybatis所依赖的包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--数据库所依赖的包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.2</version>
</dependency>
<!--日志所依赖的包-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!--lombok所依赖的包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<!--mybatis和spring的整合包:由mybatis提供-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!--由于mybatis底层还是用的jdbc:所以加入此依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
</dependencies>
②关键步骤
配置DataSource数据源
配置SqlSessionFactoryBean
使用SqlSessionTemplate进行持久化操作编写测试类测试运行结果
1.配置DataSource数据源
在spring中配置数据源,首先要选择一种具体的数据源实现技术,目前流行的数据源实现有dbcp、c3p0、Proxool , Druid等,他们都实现了功能。这里以Druid数据源为例进行讲解,首先要确保pom.xml中要有Druid的的起步依赖配置
2.配置SqlSessionFactoryBean:SqlSessionFactoryBean来自mybatis-spring的整合包
<!--配置SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
<property name="typeAliasesPackage" value="com.acoffee.maven"></property>
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration">
<property name="lazyLoadingEnabled" value="true"></property>
<property name="aggressiveLazyLoading" value="false"></property>
</bean>
</property>
</bean>
这个sqlSessionFactory组件就相当于mybatis的配置文件.
逐个列出所有的SQL映射文件比较繁琐,在SqlSessionFactoryBean的配置中可以使用mapperlocations属性扫描式加载SQL映射文件
③掌握注入映射器
MyBatis中可以使用SqlSession的getMapper(Class< T> type)方法,根据指定的映射器和映射文件直接生成实现类,这样不必自行编写映射的实现类,就可以调用映射器的方法进行功能实现。
@Test
public void testSingleParam(){
SqlSession sqlSession = MyBatisUtil.createSession();
AdminMapper adminMapper = sqlSession.getMapper(AdminMapper.class);
MyBatis-Spring中提供了MapperScannerConfigurer,它可以扫描指定包中的接口并将它直接注册为MapperFactoryBean。 MapperScannerConfigurer的配置方法如下示例所示:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.acoffee.maven.mapper"></property>
</bean>
1.basePackage属性中可以包含多个包名,多个包含之间使用逗号或分号隔开。
2.MapperScannerConfigurer会为所有又它创建的映射器实现开启自动装配,也就是说,MapperScannerConfigurer创建的所有映射器实现都会被自动注入SqlSessionFactory实例,因此在如上示例中配置DAO组件时无需显示注入SqlSessionFactory实例
3.如果只有一个sqlSessionFactory我们可以不用配置sqlSessionFactoryBeanName,它会自动依赖。但是若环境中出于不同目的配置了多个SqlSessionFactory实例,将无法进行自动装配,此时应显示指定所依赖的SqlSessionFactory实例,配置方式如下所示。
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.acoffee.maven.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
注意这里使用的是sqlSessionFactoryBeanName属性而不是sqlSessionFactory属性,正如该属性名所表达的,这个属性关注的是Bean的名称,所以为其赋值使用的是value而不是ref。
ref和value的区别?
ref是引用(指针),value是布尔、string等的值。 用ref还是value,需要看源码里这个name是什么类型的!
映射器被注册到Spring容器时,Spring会根据其接口名称为其命名,默认规则是首字母小写的非完全限定类名。 例如EmpMapper类型的组件会被默认命名为empMapper
对应关系:
代码实现:
mapper接口(数据交互层):
public interface EmpMapper {
public List<Emp> selectEmpsByDeptno(@Param("deptno") byte deptno);
public Emp selectEmpByEmpno(@Param("empno") short empno);
}
public interface DeptMapper {
public Dept selectDeptByDeptno(@Param("deptno") byte deptno);
public Dept selectDeptByDeptnoWithStep(@Param("deptno") byte deptno);
}
类:
@Data
public class Dept {
private byte deptno;
private String dname;
private String loc;
private List<Emp> emps;
}
@Data
public class Emp {
private short empno;
private String ename;
private String job;
private short mgr;
private Date hiredate;
private double sal;
private double comm;
private Dept dept;
}
接口(业务层):
public interface DeptService {
public Dept findDeptByDeptno(byte deptno);
}
实现类(业务):
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Override
public Dept findDeptByDeptno(byte deptno) {
return this.deptMapper.selectDeptByDeptno(deptno);
}
}
beans.xml文件(就相当于将mybatis-config.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置扫描包-->
<context:component-scan base-package="com.acoffee.maven"></context:component-scan>
<context:property-placeholder location="datasource.properties"></context:property-placeholder>
<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="initialSize" value="${initialSize}"></property>
<property name="maxWait" value="${maxWait}"></property>
<property name="maxActive" value="${maxActive}"></property>
<property name="minIdle" value="${minIdle}"></property>
</bean>
<!--配置SqlSessionFactory:相当于读取mybatis中的mybatis-config.xml文件-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
<property name="typeAliasesPackage" value="com.acoffee.maven"></property>
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration">
<property name="lazyLoadingEnabled" value="true"></property>
<property name="aggressiveLazyLoading" value="false"></property>
</bean>
</property>
</bean>
<!--MapperScannerConfigurer会为所有它创建的映射器实现开启自动装配-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.acoffee.maven.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
</beans>
测试类:
public class AppTest {
private Logger logger = Logger.getLogger(this.getClass());
//测试业务层
@Test
public void testSmService() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
DeptServiceImpl deptService = context.getBean("deptServiceImpl", DeptServiceImpl.class);
Dept dept = deptService.findDeptByDeptno((byte) 10);
logger.info("***********");
logger.info(dept.getDeptno());
logger.info(dept.getDname());
logger.info(dept.getLoc());
logger.info("该部门共有" + dept.getEmps().size() + "个员工");
logger.info("***********");
for (Emp emp:dept.getEmps()){
logger.info(emp.getEmpno()+"\t"+emp.getSal());
}
}
//测试数据交互层
@Test
public void testSmDao() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
DeptMapper deptMapper = context.getBean("deptMapper", DeptMapper.class);
Dept dept = deptMapper.selectDeptByDeptno((byte) 10);
logger.info("***********");
logger.info(dept.getDeptno());
logger.info(dept.getDname());
logger.info(dept.getLoc());
logger.info("该部门共有" + dept.getEmps().size() + "个员工");
logger.info("***********");
for (Emp emp:dept.getEmps()){
logger.info(emp.getEmpno()+"\t"+emp.getSal());
}
}
}
执行结果:
二、Spring对MyBatis的整合(Mybatis使用注解)
Emp 类:
@Data
public class Emp {
private short empno;
private String ename;
private String job;
private short mgr;
private Date hiredate;
private short sal;
private short comm;
private byte deptno;
private Dept depts;
}
Dept类:
@Data
public class Dept {
private byte deptno;
private String dname;
private String loc;
private List<Emp> emps;
}
deptMapper 接口(这里我们使用mapper注解:就相当于上面的DeptMapper.xml配置文件直接整合到了这个接口中):
@Mapper
public interface deptMapper {
@Insert("insert into dept(deptno,dname,loc)values(#{deptno},#{dname},#{loc})")
public void add(Dept dept);
@Delete("delete from dept where deptno=#{deptno}")
public void delete(byte deptno);
@Update("update dept set dname=#{dname},loc=#{loc} where deptno=#{deptno}")
public void update(Dept dept);
@Results({
@Result(property = "deptno",column = "deptno"),
@Result(property = "dname",column = "dname"),
@Result(property = "loc",column = "loc"),
@Result(property = "emps",column = "deptno",many = @Many(select = "com.acoffee.maven.mapper.empMapper.selectEmpByDeptno",fetchType = FetchType.EAGER))
})
@Select("select * from dept where deptno=#{deptno}")
public Dept selectOne(byte deptno);
@Select("select * from dept")
public List<Dept> selectAll();
}
empMapper 接口(与上述的deptMapper接口同理):
@Mapper
public interface empMapper {
@Select("select * from emp where deptno=#{deptno}")
public Emp selectEmpByDeptno(short deptno);
@Results({
@Result(property = "empno", column = "empno"),
@Result(property = "ename", column = "ename"),
@Result(property = "job", column = "job"),
@Result(property = "mgr", column = "mgr"),
@Result(property = "hiredate", column = "hiredate"),
@Result(property = "sal", column = "sal"),
@Result(property = "comm", column = "comm"),
@Result(property = "depts", column = "deptno", one = @One(select = "com.acoffee.maven.mapper.deptMapper.selectOne", fetchType = FetchType.LAZY))
})
@Select("select * from emp where empno=#{empno}")
public Emp selectDeptByEmpno(short empno);
}
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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置扫描包-->
<context:component-scan base-package="com.acoffee.maven"></context:component-scan>
<context:property-placeholder location="datasource.properties"></context:property-placeholder>
<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="initialSize" value="${initialSize}"></property>
<property name="maxWait" value="${maxWait}"></property>
<property name="maxActive" value="${maxActive}"></property>
<property name="minIdle" value="${minIdle}"></property>
</bean>
<!--配置SqlSessionFactory:相当于读取mybatis中的mybatis-config.xml文件-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="com.acoffee.maven"></property>
<!--configuration相当于mybatis-config.xmlsetting标签-->
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration">
<property name="lazyLoadingEnabled" value="true"></property>
<property name="aggressiveLazyLoading" value="false"></property>
</bean>
</property>
</bean>
<!--MapperScannerConfigurer会为所有又它创建的映射器实现开启自动装配-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.acoffee.maven.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
</beans>
测试文件:
public class AppTest {
private Logger logger = Logger.getLogger(this.getClass());
@Test
public void testSM() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
deptMapper deptMapper = context.getBean("deptMapper", deptMapper.class);
List<Dept> depts = deptMapper.selectAll();
for (Dept dept: depts){
logger.info(dept);
}
}
@Test
public void testAdd(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
deptMapper deptMapper = context.getBean("deptMapper", deptMapper.class);
Dept dept = new Dept();
dept.setDeptno((byte)70);
dept.setDname("Frank");
dept.setLoc("Chengdu");
deptMapper.add(dept);
}
@Test
public void testDelete(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
deptMapper deptMapper = context.getBean("deptMapper", deptMapper.class);
deptMapper.delete((byte) 70);
}
@Test
public void testUpdate(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
deptMapper deptMapper = context.getBean("deptMapper", deptMapper.class);
Dept dept = new Dept();
dept.setDeptno((byte)60);
dept.setDname("Frank");
dept.setLoc("Chengdu");
deptMapper.update(dept);
}
@Test
public void testOneToMany(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
deptMapper deptMapper = context.getBean("deptMapper", deptMapper.class);
Dept dept = deptMapper.selectOne((byte) 10);
logger.info(dept.getDeptno()+"→ → →"+dept.getDname()+"→ → →"+dept.getLoc());
for (Emp emp : dept.getEmps()) {
logger.info(emp+"\n");
}
}
@Test
public void testManyToOne(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
empMapper empMapper = context.getBean("empMapper", empMapper.class);
Emp emp = empMapper.selectDeptByEmpno((short)7369);
logger.info(emp.getEmpno()+"→ → →"+emp.getEname()+"→ → →"+emp.getSal()+"\n"+emp.getDepts());
}
}
上述的测试文件中我们只展示最后的一对多、和多对一的结果:
testOneToMany的结果:
testManyToOne的结果:
多对一结果中出现列表的原因是不要以为 他是很多个对象 其实这个列表是一个Dept对象,出现列表的原因只是因为出现了这个部门(Dept对象)展示出了所有的Emp对象,为什么这个结果会展示出来呢?是因为我们在deptMapper接口中的selectOne中有Result注解,所以就将这个Dept对象中的所有的Emp对象都展示出来了,就像俄罗斯套娃一样。