MyBatis和Spring整合 - 使用Mapper代理

MyBatis和Spring的优点

工欲善其事,必先利其器。开发环境配置好才能正常地编辑和编译代码,就像盖起一座高楼大厦最重要的是打地基。假如要开发Web应用,那么基本离不开数据的存储和处理,也就是离不开数据库。MyBatis解决了JDBC硬编码的问题,把SQL语句配置在了xml文件里,同时mapper映射配置文件可以将数据库操作结果集映射到相应的Java实体类中,十分方便。和Spring整合后,数据库连接池的配置将会放到Spring中,封装JDBC对事务的处理。MyBatis通过SqlSessionFactory来加载全局配置文件和映射配置文件等,初始化出SqlSession会话,提供数据库连接,Spring可以负责管理SqlSessionFactory,管理mapper映射文件,提供事务处理。所以MyBatis和Spring的整合,相得益彰,这篇日志就来看下两者的整合过程,以及使用mapper代理配置后,如何更方便地进行事务处理。

 

Spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring配置文件 -->
<!-- 添加Spring的xmlns和xsi信息 -->
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc-3.2xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context-3.2.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">

	<!-- 加载数据库静态属性配置文件 -->
	<context:property-placeholder location="classpath:db.properties" />
	

首先是Spring配置文件,开头声明了xml版本信息1.0和编码信息UTF-8后,接下来在beans标签对中配置xmlns文档信息(类似于URL)。xsi是模式文档信息,即xml规范。之后第21行,配置数据库连接信息,和MyBatis一样,我们把数据库的连接的配置信息放在了外部的文件里,在Spring配置文件中,通过读取外部静态属性文件,来和数据可建立连接,进行交互。Spring使用的也是DBCP数据库连接池(或者说数据源),这样做的好处是,数据库连接配置信息无需写入到应用程序的代码中,与SQL语句无需硬编码道应用程序代码中一样。来看看保存着数据库连接配置信息的外部静态属性文件:

#JDBC 
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/mybatis_test?characterEncoding=utf-8&useSSL=false
jdbc.username = root
jdbc.password = 12345

用户名密码等信息的参数都配置在了这里面,Spring只要读取它们即可。

回到Spring配置文件上,下一个标签配置数据库连接池:

<!-- 数据源 -->
	<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
		destroy-method="close">
		<property name="driverClassName" value="${jdbc.driver}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>

数据源id为“dataSource”,配置class为DBCP数据源管理类,指定销毁方法名“close”。可以看到,数据库驱动,用户名,密码等信息,我们都可以通过“${ }”的方式读取,把前面db.properties文件中的参数注入到变量中,前提是我们前面配置了数据库连接配置的外部文件信息。最后到会话工厂SqlSessionFactory的配置,前面说到,Spring负责管理SqlSessionFactory,提供数据库的连接和事务管理,数据库连接信息我们已经配置好了,事务管理方面接着来配置:

<!-- 会话工厂sqlSessionFactory -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 加载MyBatis的全局配置文件 -->
		<property name="configLocation" value="mybatis/SqlMapConfig.xml" />
		<!-- 数据源文件 -->
		<property name="dataSource" ref="dataSource" />
	</bean>

对数据库的操作,例如SQL语句,mapper映射配置文件等,我们都配置在了MyBatis的全局配置文件中了,在Spring配置文件里,我们直接把这些东西加载进来。

DAO层配置

由于事务处理部分交由了Spring管理,所以要编写数据库交互层Dao层,它是一个接口,提供了数据库操作的增删查改等方法。以这里的用户查询为例,首先新建一个Dao层接口interface:

package com.sm.dao;

import java.util.List;
import com.sm.po.User;

// 用户管理Dao接口
public interface UserDao {
	public User findUserById(int id) throws Exception;
	public List<User> multiSearch() throws Exception;
}

里面定义了数据库操作的抽象方法,接着就要创建接口的实现类:

package com.sm.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import com.sm.po.User;

// 查询用户信息UserDap接口的实现类
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
	// 查询单个指定id用户
	@Override
	public User findUserById(int id) throws Exception {
		// 继承SqlSessionDaoSupport类, 通过this.getSqlSession()得到sqlSession
		SqlSession sqlSession = this.getSqlSession();
		User user = sqlSession.selectOne("findUserById", id);
		
		return user;
	}

	@Override
	public List<User> multiSearch() throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

}

实现类实现UserDao接口,同时继承SqlSessionDaoSupport类,这个类是Spring和MyBatis整合包里的,作用是为Spring提供SqlSessionFactory对象,从而生成会话SqlSession,最后通过SqlSession会话实例执行数据库操作,这部分是不是很熟悉?在MyBatis里就是这样做的,现在整合到了Spring中去了。最后返回查询结果集。

接口和对应的实现类完成,最后要在Spring的配置文件中配置这个接口:

<!-- 原始Dao接口 -->
	<bean id="userDao" class="com.sm.dao.UserDaoImpl">
		<property name="SqlSessionFactory" ref="sqlSessionFactory"></property>
	</bean>

告诉Spring把SqlSessionFactory作为参数传入该接口,这样接口实现类才能继承SqlSessionFactory类。

MyBatis配置文件

全局配置文件SqlMapConfig

回到了熟悉的MyBatis(前段时间一直都陪伴着它啊哈哈),那我们就和以前一样,从全局配置文件开始配置吧:

<?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>
	<settings>
		<!-- 配置日志输出模式logImpl为LOG4J -->
		<setting name="logImpl" value="LOG4J" />
		<!-- 配置二级缓存 -->
		<setting name="cacheEnabled" value="true"/>
		<!-- 深度延迟加载 -->
		<!-- 打开延迟加载 -->
		<setting name="lazyLoadingEnabled" value="true"/>
		<!-- 积极加载/按需加载配置 -->
		<setting name="aggressiveLazyLoading" value="false"/>
	</settings>
	
	<!-- 批量定义别名  -->
	<typeAliases>
		<package name="com.sm.po"/>
	</typeAliases>
	
	<mappers>
		<mapper resource="sqlmap/UserMapper.xml"/>
	</mappers>
</configuration>

MyBatis的全局配置文件简单了好多,因为数据源配置,DBCP等信息都整合到了Spring中去了,由Spring来管理,在MyBatis的全局配置文件中,我们只简单地配置日志信息,一些延迟加载,二级缓存信息即可,typeAliases配置别名,直接让Java实体类包作为别名扫描路径,批量配置别名,这样配置后,报下的所有Java实体类都可以拥有一个(除开头字母小写外,其余相同)别名。最后是配置mapper文件的路径,可以单一配置,也可以使用package标签批量配置。

Mapper映射配置文件

下一步,编写mapper映射配置文件,作为简单的MyBatis和Spring整合,我们写个简单的查询语句和映射结果集配置即可:

<?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.sm.po.UserMapper">

	<resultMap type="com.sm.po.User" id="userResult">
		<id property="id" column="user_id"/>
		<result property="username" column="user_name"/>
		<result property="gender" column="user_gender"/>
		<result property="email" column="user_email"/>
		<result property="province" column="user_province"/>
		<result property="city" column="user_city"/>
	</resultMap>
	
    <select id="findUserById" parameterType="int" resultMap="userResult">
        SELECT
        	U.username as user_name,  
        	U.gender as user_gender,  
        	U.email as user_email, 
        	U.province as user_province, 
        	U.city as user_city
         FROM USER U WHERE id=#{id};
    </select>
    
    <select id="multiSearch" resultType="user">
    	SELECT * FROM USER;
    </select>
    
</mapper>

resultMap配置property和column的映射关系,也就是数据库字段和结果集实体类的属性映射关系,主键是id。下面一条简单的查询语句,根据输入id参数来查询相应的用户信息。

测试用例

最后到测试用例,测试用例也比较简单,有了以前MyBatis的基础后,可以轻松写出简单查询用例:

package com.sm.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sm.dao.UserDao;
import com.sm.po.User;

public class UserServiceTest {
	// 先获取Spring配置文件对象
	private ApplicationContext applicationContext;
	
	// 使用注解@Before,在执行本类中所有测试方法之前,会先执行这个方法
	public void setup() throws Exception {
		applicationContext = new 
		ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
	}
	
	@Test
	public void FindUserByIdTest() throws Exception {
		setup();
		// 通过配置资源对象获取userDao对象
		UserDao userDao = (UserDao) applicationContext.getBean("userDao");
		// 调用查询方法
		User user = userDao.findUserById(4);
		
		StringBuffer result = new StringBuffer();
		result.append("用户名: " + user.getUsername() + "\r\n");
		result.append("性别: " + user.getGender() + "\r\n");
		result.append("电子邮箱: " + user.getEmail() + "\r\n");
		result.append("省份: " + user.getProvince() + "\r\n");
		result.append("城市: " + user.getCity() + "\r\n");
		
		System.out.println(result.toString());
	}
	public static void main(String[] args) throws Exception {
		UserServiceTest userTest = new UserServiceTest();
		userTest.FindUserByIdTest();

	}

}

因为我们的事务处理交由了Spring管理,所以先要获取Spring的配置文件,就像之前MyBatis先要通过自己的配置文件初始化SqlSessionFactory然后得到会话SqlSession那样。获取Spring配置文件后,调用getBean()方法获得数据库交互层Dao层的实例后,就可以通过其调用自己写的查询方法了。

 

Mapper代理配置

从上面Dao层的实现类UserDaoImpl中你可以看到,执行数据库操作是通过SqlSession类的实例来实现,那么它可不可以像MyBatis那样,也是用动态代理呢?可以。Spring有自己的Mapper批量扫面器,首先我们来配置一下:

<!-- Mapper扫描器 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<!-- 指定扫描的包名,如果扫描多个包,包之间使用半角逗号分隔 -->
		<property name="basePackage" value="com.sm.mapper"/>
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
	</bean>

配置批量扫描com.sm.mapper包下的接口,之后就可以去配置Mapper代理接口了:

接口名要和Mapper映射配置文件的namespace一致。最后到测试用例:

package com.sm.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sm.dao.UserDao;
import com.sm.mapper.UserMapper;
import com.sm.po.User;

public class UserServiceTest {
	// 先获取Spring配置文件对象
	private ApplicationContext applicationContext;
	
	// 使用注解@Before,在执行本类中所有测试方法之前,会先执行这个方法
	public void setup() throws Exception {
		applicationContext = new 
		ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
	}
	
	@Test
	public void FindUserByIdTest() throws Exception {
		setup();
		// 通过配置资源对象获取userDao对象
		//动态代理方法
		UserMapper userMapper = (UserMapper) applicationContext.getBean("userDao");
		User user = userMapper.findUserById(4);
		
		StringBuffer result = new StringBuffer();
		result.append("用户名: " + user.getUsername() + "\r\n");
		result.append("性别: " + user.getGender() + "\r\n");
		result.append("电子邮箱: " + user.getEmail() + "\r\n");
		result.append("省份: " + user.getProvince() + "\r\n");
		result.append("城市: " + user.getCity() + "\r\n");
		
		System.out.println(result.toString());
	}
	public static void main(String[] args) throws Exception {
		UserServiceTest userTest = new UserServiceTest();
		userTest.FindUserByIdTest();

	}

}

使用动态代理后,我们获取的就不是接口的实现类UserDaoImpl的实例了,而是直接获取代理对象UserMapper的实例,然后就可以通过该实例调用自己的查询方法。

 

完整代码已上传GitHub:

https://github.com/justinzengtm/SSM-Framework/tree/master/MyBatisAndSpring

发布了97 篇原创文章 · 获赞 71 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/justinzengTM/article/details/100868020