MyBatis 的真正强大之处在于它的映射语句,这也是它的魔力所在。由于它的映射语句异常强大,映射器的XML 文件就显得相对简单。如果将其与具有相同功能的JDBC 代码进行对比, 立刻就会发现,使用这种方法节省了将近95%的代码量。 MyBatis 就是针对SQL构建的,并且比普通的方法做的更好。
MyBatis 3.0 的一个最大变化,就是支持使用接口来调用方法。MyBatis 使用Java 的动态代理可以直接通过接口来调用相应的方法,不需要提供接口的实现类,更不需要在实现类中使用 SqlSession以通过命名空间间接调用。
二、xml示例: 2.1 创建数据库创建如下的数据库,并插入数据:
CREATE TABLE `sys_user` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户 ID', `user_name` varchar(50) DEFAULT NULL COMMENT '用户名', `user_password` varchar(50) DEFAULT NULL COMMENT '密码', `user_email` varchar(50) DEFAULT NULL COMMENT '邮箱', `user_info` text COMMENT '简介', `head_img` blob COMMENT '头像', `create_time` datetime DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1002 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户农';2.2 创建实体类
创建对应sys_user数据表的实体类:
public class SysUser {
private Long id;
private String userName;
private String userPassword;
private String userEmail;
private String userInfo;
private byte[] headImg;
private Date createTime;
public Long getId() {
return id;
}
public String getUserName() {
return userName;
}
public String getUserPassword() {
return userPassword;
}
public String getUserEmail() {
return userEmail;
}
public String getUserInfo() {
return userInfo;
}
public byte[] getHeadImg() {
return headImg;
}
public Date getCreateTime() {
return createTime;
}
public void setId(Long id) {
this.id = id;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
public void setUserInfo(String userInfo) {
this.userInfo = userInfo;
}
public void setHeadImg(byte[] headImg) {
this.headImg = headImg;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
}
对于 SysUser 实体类,在后面使用这些对象的时候,可以通过resultMap 对数据库的列和类的宇段配置映射关系。
2.3 创建UserMapper.xml映射文件 需要注意的是<mapper>根标签的namespace 属性。当Mapper 接口和XML 文件关联的
时候,命名空间namespace 的值就需要配置成接口的全限定名称。
xml映射文件中标签含义:
2.4 创建XML文件对应的接口类public interface UserMapper {
SysUser selectById(Long id);
}
接口中定义的返回值类型必须和泊位中配置的resultType 类型一致,否则就会因为类型不一致而抛出异常。 xml方式下,返回值类型是由XML 中的resultType (或 resultMap 中的type)决定的,不是由接口中写的返回值类型决定的
2.5 MyBatis主配置文件在配置文件中,我们可以直接在
这种配置方式需要将所有映射文件一一列举出来,如果增加了新的映射文件,还需要注意在此处进行配置,操作起来比较麻烦。由于此处所有的XML映射文件都有对应的Mapper 接口,所以还有一种更简单的配置方式,代码如下:
这种配置方式会先查找包com.wyf.mybaties.mapper下所有接口,循环对接口进行如下操作:
- 判断接口对应的命名空间是否己经存在,如果存在就抛出异常,不存在就继续进行接下来的操作;加载接口对应的XML映射文件, 将接口全限定名转换为路径。 例如, 将接口com.wyf.mybaties.mapper.UserMapper 转换为com/wyf/mybaties/mapper/UserMapper. xml,
然后以.xml 为后缀搜索XML 资源,如果找到就解析XML。处理接口中的注解方法。
我们需要查询数据库中的数据。 在使用纯粹的 JDBC 时,需要写查询语句,并且对结果集进行手动处理, 将结果映射到对象的属性中。使用MyBatis 时,只需要在XML 中添加一个select 元素,写一个SQL, 再做一些简单的配置,就可以将查询的结果直接映射到对象中。
如上节示例,我们在xml映射文件以及对应的接口文件添加了一个根据用户 id 查询用户信息的简单方法。
前面创建接口和XML时提到过,接口和XML是通过将namespace 的值设置为接口的全限定名称来进行关联的,那么接口中方法和XML又是怎么关联的呢?
通过前文代码,我们可以发现XML 中的 select 标签的id 属性值和定义的接口方法名是一样的MyBatis ,就是通过这种方式将接口方法和XML中定义的SQL语句关联到一起的,如果接口方法没有和XML 中的id 属性值相对应,启动程序便会报错。映射XML和接口的命名需要符合如下规则:
当只使用XML而不使用接口的时候, namespace 的值可以设置为任意不重复的名称。标签的id 属性值在任何时候都不能出现英文句号“.”,并且同一个命名空间下不能出现重复的id。因为接口方法是可以重载的,所以接口中可以出现多个同名但参数不同的方法,但是XML 中 id 的值不能重复,因而接口中的所有同名方法会对应着XML 中的同一个id的方法。最常见的用法就是,同名方法中其中一个方法增加一个 RowBound 类型的参数用于实现分页查询。
测试代码如下:
public class baseMapperTest {
private static SqlSessionFactory sqlSessionFactory;
@BeforeClass
public static void init(){
try{
Reader reader= Resources.getResourceAsReader("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
reader.close();
}catch(IOException ex){
ex.printStackTrace();
}
}
public SqlSession getSqlSession (){
return sqlSessionFactory.openSession();
}
}
测试:
public class UserMapperTest extends baseMapperTest{
@Test
public void TestSelectById(){
//获取SqlSession
SqlSession sqlSession = getSqlSession();
try{
//获取UserMapper接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用selectByid 方法,查询id = 1 的用户
SysUser user = userMapper.selectById(1l);
System.out.println(user.getCreateTime());
}finally {
sqlSession.close();
}
}
}
3.2 Insert方法
我们可以在UserMapper.xml中添加如下代码:
insert into sys_user( user_name, user_password, user_email, user_info, head_img, create_time) values( #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP})
此处<insert>中的 SQL 就是一个简单的 INSERT 语句,将所有的列都列举出来, 在values 中通过#{property}方式从参数中取出属性的值。
为了防止类型错误,对于一些特殊的数据类型,建议指定具体的jdbcType值。 例如headimg 指定BLOB 类型, createTime 指定TIMESTAMP 类型。
我们在与UserMapper.xml相关联的接口中,添加对应的方法:
int insert(SysUser sysUser);
编写测试代码:
@Test
public void InsertToUser(){
//获取SqlSession
SqlSession sqlSession = getSqlSession();
try{
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
SysUser sysUser = new SysUser();
sysUser.setUserName("wyf");
sysUser.setUserPassword("111111");
sysUser.setUserEmail("wyf@book.com");
sysUser.setUserInfo("wyf info");
sysUser.setHeadImg(new byte[]{1,2,3}); //实际是一张图片
sysUser.setCreateTime(new Date());
//将新建的对象插入数据库中,返回值result 是执行的SQL 影响的行数
int res = userMapper.insert(sysUser);
System.out.println("数据插入执行结果:"+res);
}finally {
//默认的sqlSessionFactory.openSession()是不自动提交的
//因此不手动执行commit 也不会提交到数据库
sqlSession.commit(); //提交数据插入
sqlSession.close();
}
}
3.3 upDate方法
在UserMapper.xml映射文件中添加以下方法:
update sys_user set user_name= #{userName} , user_password= #{userPassword}, user_email = #{userEmail} , user_info= #{userInfo} , head_img = #{headImg , jdbcType=BLOB} , create_time = #{createTime , jdbcType=TIMESTAMP} where id = #{id}
在UserMapper.xml映射文件对应的接口文件中添加相应的方法:
int updateById(SysUser sysUser);
编写测试代码:
@Test
public void UpDateToUser(){
//获取SqlSession
SqlSession sqlSession = getSqlSession();
try{
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//从数据库查询获取一个user对象
SysUser sysUser = userMapper.selectById(1L);
//修改
sysUser.setUserName("wyf_test");
sysUser.setUserPassword("123456");
sysUser.setUserEmail("wyf_test@book.com");
//更新数据,返回影响行数
int res = userMapper.updateById(sysUser);
System.out.println("数据修改执行影响结果:"+res);
}finally {
//默认的sqlSessionFactory.openSession()是不自动提交的
//因此不手动执行commit 也不会提交到数据库
sqlSession.commit(); //提交数据插入
sqlSession.close();
}
}
3.4 delete方法
在UserMapper.xml文件中添加以下方法:
delete from sys_user where id = #{id}
在UserMapper.xml映射文件对应的接口文件中添加相应的方法:
int deleteById(Long id);
测试代码:
@Test
public void DeleteToUser(){
//获取SqlSession
SqlSession sqlSession = getSqlSession();
try{
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//从数据库查询获取一个user对象
SysUser sysUser = userMapper.selectById(1L);
//删除对象
int res = userMapper.deleteById(sysUser.getId());
System.out.println("数据修改执行影响结果:"+res);
}finally {
//默认的sqlSessionFactory.openSession()是不自动提交的
//因此不手动执行commit 也不会提交到数据库
sqlSession.commit(); //提交数据
sqlSession.close();
}
}
3.5 多个接口参数的用法
通过观察,不难发现目前所列举的接口中方法的参数只有一个,参数的类型可以分为两种:一种是基本类型,另一种是JavaBean。
当参数是一个基本类型的时候,它在XML文件中对应的SQL 语句只会使用一个参数,例如delete 方法。当参数是一个JavaBean 类型的时候,它在XML文件中对应的SQL语句会有多个参数,例如insert、 update 方法。
在实际应用中经常会遇到使用多个参数的情况。之前例子中,我们将多个参数合并到一个JavaBean 中,并使用这个JavaBean 作为接口方法的参数。这种方法用起来很方便,但并不适合全部的情况,因为不能只为了两三个参数去创建新的JavaBean 类,因此对于参数比较少的情况,还有两种方式可以采用:使用Map 类型作为参数或使用@Param 注解。
接口方法中,参数要添加注解:
List selectRolesByUserIdAndRoleEnabled(@Param("userId")Long userId, @Param("enabled")Integer enabled);
给参数配置@Param注解后, MyBatis 就会自动将参数封装成Map 类型,@Param 注解值
会作为Map 中的key,因此在SQL 部分就可以通过配置的注解值来使用参数。
本文介绍了MyBatis使用XML的配置方式,并基于其实现了select、insert、update和delete操作。



