赞
踩
MyBatis 的真正强大之处在于它的映射语句,这也是它的魔力所在。由于它的映射语句异常强大,映射器的XML 文件就显得相对简单。如果将其与具有相同功能的JDBC 代码进行对比, 立刻就会发现,使用这种方法节省了将近95%的代码量。 MyBatis 就是针对SQL构建的,并且比普通的方法做的更好。
MyBatis 3.0 的一个最大变化,就是支持使用接口来调用方法。MyBatis 使用Java 的动态代理可以直接通过接口来调用相应的方法,不需要提供接口的实现类,更不需要在实现类中使用 SqlSession以通过命名空间间接调用。
创建如下的数据库,并插入数据:
- 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='用户农';
创建对应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 对数据库的列和类的宇段配置映射关系。
- <?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.wyf.mybaties.mapper.UserMapper">
- <resultMap id="userMap" type="com.wyf.mybaties.model.SysUser">
- <id property="id" column="id"/>
- <result property="userName" column="user_name"/>
- <result property="userPassword" column="user_password"/>
- <result property="userEmail" column="user_email"/>
- <result property="userInfo" column="user_info"/>
- <result property="headImg" column="head_img" jdbcType="BLOB"/>
- <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
- </resultMap>
-
- <!-- select查询 -->
- <select id="selectById" resultMap="userMap">
- select * from sys_user where id = #{id}
- </select>
-
- </mapper>

需要注意的是<mapper>根标签的namespace 属性。当Mapper 接口和XML 文件关联的
时候,命名空间namespace 的值就需要配置成接口的全限定名称。
xml映射文件中标签含义:
resultMap 标签用于配置Java 对象的属性和查询结果列的对应关系,通过 resultMap中配置的column 和property 可以将查询列的值映射到type 对象的属性上。
- public interface UserMapper {
- /**
- * 通过ID查询用户
- * @param id
- * @return
- */
- SysUser selectById(Long id);
-
- }
接口中定义的返回值类型必须和泊位中配置的resultType 类型一致,否则就会因为类型不一致而抛出异常。 xml方式下,返回值类型是由XML 中的resultType (或 resultMap 中的type)决定的,不是由接口中写的返回值类型决定的
- <?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>
- <setting name="logImpl" value="LOG4J"/>
- </settings>
-
- <typeAliases>
- <package name="com.wyf.mybaties.model"/>
- </typeAliases>
-
- <environments default="development">
- <environment id="development">
- <transactionManager type="JDBC">
- <property name="" value=""/>
- </transactionManager>
- <dataSource type="UNPOOLED">
- <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
- <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false"/>
- <property name="username" value="root"/>
- <property name="password" value="password"/>
- </dataSource>
- </environment>
- </environments>
-
- <mappers>
- <package name="com.wyf.mybaties.mapper" />
- </mappers>
-
- </configuration>

在配置文件中,我们可以直接在<mappers>指定映射文件,如下
<mappers>
<mapper resource=”com/wyf/mybaties/mapper/CountryMapper.xml ” / >
<mapper resource=”com/wyf/mybaties/mapper/UserMapper.xml ” / >
<mapper resource=”com/wyf/mybaties/mapper/RoleMapper.xml” />
<mapper resource=”com/wyf/mybaties/mapper/PrivilegeMapper.xml ” />
<mapper resource=”com/wyf/mybaties/mapper/UserRoleMapper.xml ” />
<mapper resource=”com/wyf/mybaties/mapper/RolePrivilegeMapper.xml ” />
</mappers>
这种配置方式需要将所有映射文件一一列举出来,如果增加了新的映射文件,还需要注意在此处进行配置,操作起来比较麻烦。由于此处所有的XML映射文件都有对应的Mapper 接口,所以还有一种更简单的配置方式,代码如下:
<mappers>
<package name="com.wyf.mybaties.mapper" />
</mappers>
这种配置方式会先查找包com.wyf.mybaties.mapper下所有接口,循环对接口进行如下操作:
我们需要查询数据库中的数据。 在使用纯粹的 JDBC 时,需要写查询语句,并且对结果集进行手动处理, 将结果映射到对象的属性中。使用MyBatis 时,只需要在XML 中添加一个select 元素,写一个SQL, 再做一些简单的配置,就可以将查询的结果直接映射到对象中。
如上节示例,我们在xml映射文件以及对应的接口文件添加了一个根据用户 id 查询用户信息的简单方法。
前面创建接口和XML时提到过,接口和XML是通过将namespace 的值设置为接口的全限定名称来进行关联的,那么接口中方法和XML又是怎么关联的呢?
通过前文代码,我们可以发现XML 中的 select 标签的id 属性值和定义的接口方法名是一样的MyBatis ,就是通过这种方式将接口方法和XML中定义的SQL语句关联到一起的,如果接口方法没有和XML 中的id 属性值相对应,启动程序便会报错。映射XML和接口的命名需要符合如下规则:
测试代码如下:
- /**
- * 基础测试类
- */
- 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();
- }
- }
-
- /**
- * 由SqlSessionFactory工厂对象,生产SqlSession
- * @return
- */
- 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();
- }
- }
- }

我们可以在UserMapper.xml中添加如下代码:
- <!-- insert数据插入 -->
- <insert id="insert">
- 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>
此处<insert>中的 SQL 就是一个简单的 INSERT 语句,将所有的列都列举出来, 在values 中通过#{property}方式从参数中取出属性的值。
为了防止类型错误,对于一些特殊的数据类型,建议指定具体的jdbcType值。 例如headimg 指定BLOB 类型, createTime 指定TIMESTAMP 类型。
我们在与UserMapper.xml相关联的接口中,添加对应的方法:
- /**
- * 新增用户
- *
- * @param sysUser
- * @return 返回影响行数
- */
- int insert(SysUser sysUser);
编写测试代码:
- /**
- * insert方法测试
- */
- @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();
- }
- }

在UserMapper.xml映射文件中添加以下方法:
- <!-- update 数据更新 -->
- <update id="updateById">
- 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}
- </update>
在UserMapper.xml映射文件对应的接口文件中添加相应的方法:
- /**
- * 根据主键更新
- *
- * @param sysUser
- * @return
- */
- int updateById(SysUser sysUser);
编写测试代码:
- /**
- * Update方法测试
- */
- @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();
- }
- }

在UserMapper.xml文件中添加以下方法:
- <!-- delete删除数据 -->
- <delete id="deleteById">
- delete from sys_user where id = #{id}
- </delete>
在UserMapper.xml映射文件对应的接口文件中添加相应的方法:
- /**
- * 通过主键删除
- *
- * @param id
- * @return
- */
- int deleteById(Long id);
测试代码:
- /**
- * delete方法测试
- */
- @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();
- }
- }

通过观察,不难发现目前所列举的接口中方法的参数只有一个,参数的类型可以分为两种:一种是基本类型,另一种是JavaBean。
当参数是一个基本类型的时候,它在XML文件中对应的SQL 语句只会使用一个参数,例如delete 方法。当参数是一个JavaBean 类型的时候,它在XML文件中对应的SQL语句会有多个参数,例如insert、 update 方法。
在实际应用中经常会遇到使用多个参数的情况。之前例子中,我们将多个参数合并到一个JavaBean 中,并使用这个JavaBean 作为接口方法的参数。这种方法用起来很方便,但并不适合全部的情况,因为不能只为了两三个参数去创建新的JavaBean 类,因此对于参数比较少的情况,还有两种方式可以采用:使用Map 类型作为参数或使用@Param 注解。
- <!-- 多参数 -->
- <select id="selectRolesByUserIdAndRoleEnabled" resultType="com.wyf.mybaties.model.SysRole">
- select
- r.id,
- r.role_name roleName,
- r.enabled,
- r.create_by createBy,
- r.create_time createTime
- from sys_user u
- inner join sys_user_role ur on u.id = ur.user_id
- inner join sys_role r on ur.role_id = r.id
- where u.id = #{userId} and r.enabled = #{enabled}
- </select>
接口方法中,参数要添加注解:
- /**
- * 根据用户 id 和 角色的 enabled 状态获取用户的角色
- *
- * @param userId
- * @param enabled
- * @return
- */
- List<SysRole> selectRolesByUserIdAndRoleEnabled(@Param("userId")Long userId, @Param("enabled")Integer enabled);
给参数配置@Param注解后, MyBatis 就会自动将参数封装成Map 类型,@Param 注解值
会作为Map 中的key,因此在SQL 部分就可以通过配置的注解值来使用参数。
本文介绍了MyBatis使用XML的配置方式,并基于其实现了select、insert、update和delete操作。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。