极简Mybatis之旅(一):CRUD

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 摘要 最近在研究mybatis框架,作为一个优秀ORM框架,mybatis很多优秀的设计思想值得借鉴。 mybatis的配置文件里,主要是config和mapper。config定义了全局参数:数据源类型(POOL, UNPOOLED, JNDI)、事务管理类型(默认为managed)、库url、账户信息和mapper文件路径。

摘要

最近在研究mybatis框架,作为一个优秀ORM框架,mybatis很多优秀的设计思想值得借鉴。

mybatis的配置文件里,主要是config和mapper。config定义了全局参数:数据源类型(POOL, UNPOOLED, JNDI)、事务管理类型(默认为managed)、库url、账户信息和mapper文件路径。

config配置

// config.xml
<configuration>
    <environments default="classfly">
        <environment id="classfly">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8" />
                <property name="username" value="yourusername" />
                <property name="password" value="yourpassword" />
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mapper/UserMapper.xml" />
    </mappers>
</configuration>

DBNAME='test',是mybatis默认分配的库:
image

mapper配置

首先我们要问自己以下三个问题:

  • 为什么要配置mapper文件?
  • 怎么配置mapper文件?
  • mybatis如何解析mapper文件?

mapper文件的作用

mapper文件提供一种持久化层与应用层的"通信协议",通过mysql关键字resultMap, parameterType等维护应用代码DO对象与持久化存储数据之间的关联关系。

mapper文件里定义了select, insert, update, delete四种常用的DML语句,并定义statement={mapper namespace}.{operation}实现在应用代码层执行调用DB操作。

配置mapper文件

这里先给出测试用例用到的mapper配置文件的关键部分:

<!-- 代码清单-1 -->
<mapper namespace="com.classfly.mapper.UserMapper">
    <resultMap id="user" type="pojo.User">
        <result column="user_id" property="userId" />
        <result column="user_name" property="userName" />
        <result column="password" property="password" />
        <result column="age" property="age" />
    </resultMap>

    <select id="query" resultMap="user">
        SELECT * FROM user;
    </select>

    <insert id="insert" parameterType="pojo.User">
        insert into user
          (
            user_id,
            user_name,
            password,
            age)
        values
          (
            #{userId},
            #{userName},
            #{password},
            #{age}
          )
        <selectKey resultType="pojo.User" keyProperty="id" order="AFTER">
            select LAST_INSERT_ID() as id
        </selectKey>
    </insert>

    <update id="update" parameterType="pojo.User">
        UPDATE user
        SET user_name = #{userName}
          , password = #{password}
          , age = #{age}
        WHERE user_id = #{userId}
    </update>

    <delete id="delete">
        DELETE FROM user
        WHERE user_id = #{userId}
    </delete>
</mapper>

mapper namespace定义了DML语句的作用范围,那如果两个不同的mapper文件定义相同的namespace会发生什么?由于mysql保持namespace的全局唯一性,所以在解析mapper文件时mysql会抛异常提示开发者修改mapper文件以保持namespace的全局唯一性。

resultMap

resultMap关键字将代码和持久化层的数据映射抽象出来,用户无需关心两者之间如何映射。

我们可以使用HashMap完成代码和持久化层的数据映射关系,不但缺乏通用型且代码层需要将对象转换成map结构。resultMap接受HashMap结构和JavaBean或者POJO对象,提供轻量级的参数映射方案。

resultMap有"别名"的功能,你无需每个DML都写一大串的映射语句,秉着"仅定义一次"的原则,我们可以这么做:

// config.xml
<typeAlias type="pojo.User" alias="User"/>

// 用typeAlias的User别名替换了resultMap中的user
<select id="query" resultType="User">
    SELECT * FROM user ORDER BY id DESC
</select>

Now if only the world was always that simple!

当POJO类成员变量并未完全和Table列名"对齐"时,可通过定义resultMap的方式来实现mapper:

<resultMap id="user" type="User">
  <result property="userId" column="user_id" />
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>

<select id="query" resultMap="user">
    SELECT * FROM user ORDER BY id DESC
</select>

'#'和'$'

从"代码清单-1"里可以看出,#和$
均可实现POJO字段和DB表列名的映射关系。#将参数部分用?替换,而$仅根据执行sql时通过POJO对象透传的值进行字符串替换,容易被注入恶意代码,不可取!如:

select * from ${tableName} where name = #{name}

如果tableName='user; delete user; --',最终sql语句变为:

select * from user; delete user; -- where name = #{name}

导致user整张表数据被删除。

mybatis如何解析mapper文件

To be continued...

测试用例

/**
 * Created by fujianbo on 2018/4/22.
 *
 * @author fujianbo
 * @date 2018/04/22
 */
public class TestMybatis {
    @Test
    public void testQuery() {
        SqlSession sqlSession = buildMySqlEnv("config.xml");
        List<User> userList = sqlSession.selectList("com.classfly.mapper.UserMapper.query");
        for (User p : userList) {
            System.out.println(p);
        }
    }

    @Test
    public void testInsert() {
        SqlSession sqlSession = buildMySqlEnv("config.xml");
        User user = new User();
        user.setUserId(124L);
        user.setAge(26);
        user.setPassword("test_123");
        user.setUserName("芸Rey");
        if (sqlSession.insert("com.classfly.mapper.UserMapper.insert", user) > 0) {
            sqlSession.commit();
        }
    }

    @Test
    public void testUpdate() {
        SqlSession sqlSession = buildMySqlEnv("config.xml");
        User user = new User();
        user.setUserId(124L);
        user.setAge(26);
        user.setUserName("芸Rey");
        user.setPassword("test_modified");
        if (sqlSession.update("com.classfly.mapper.UserMapper.update", user) > 0) {
            sqlSession.commit();
        }
    }

    @Test
    public void testDelete() {
        SqlSession sqlSession = buildMySqlEnv("config.xml");
        User user = new User();
        user.setUserId(123L);
        if (sqlSession.update("com.classfly.mapper.UserMapper.delete", user) > 0) {
            sqlSession.commit();
        }
    }

    private static SqlSession buildMySqlEnv(String resource) {
        try {
            return new SqlSessionFactoryBuilder()
                .build(org.apache.ibatis.io.Resources.getResourceAsStream(resource))
                .openSession();
        } catch (IOException e) {
            System.out.printf("Failed to build mysql environment!");
            return null;
        }
    }
}

代码链接实现

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
7月前
|
SQL Java 数据库连接
|
7月前
MyBatisPlus-标准数据层CRUD功能制作
MyBatisPlus-标准数据层CRUD功能制作
76 0
|
7月前
|
SQL Java 数据库连接
JAVAEE框架技术之7-myBatis ORM框架入门基础CRUD
JAVAEE框架技术之7-myBatis ORM框架入门基础CRUD
165 0
JAVAEE框架技术之7-myBatis ORM框架入门基础CRUD
|
7月前
|
XML Java 数据库连接
MyBatis深入探索:原生API与注解方式实现CRUD操作
MyBatis深入探索:原生API与注解方式实现CRUD操作
124 0
|
7月前
|
Java 关系型数据库 数据库连接
【MyBatisPlus 】MyBatisPlus CRUD 工程使用
【1月更文挑战第19天】【MyBatisPlus 】MyBatisPlus CRUD 工程使用
|
2月前
|
SQL Java 数据库连接
MyBatis-Plus:简化 CRUD 操作的艺术
MyBatis-Plus 是一个基于 MyBatis 的增强工具,它旨在简化 MyBatis 的使用,提高开发效率。
80 1
MyBatis-Plus:简化 CRUD 操作的艺术
|
2月前
|
SQL Java 数据库连接
Mybatis方式完成CRUD操作
Mybatis方式完成CRUD操作
49 0
|
6月前
|
缓存 Java 数据库连接
我们后端程序员不是操作MyBatis的CRUD Boy
大家好,我是南哥。一个对Java程序员进阶成长颇有研究的人,今天我们接着新的一篇Java进阶指南。为啥都戏称后端是CRUD Boy?难道就因为天天怼着数据库CRUD吗?要我说,是这个岗位的位置要的就是你CRUD,你不得不CRUD。哪有公司天天能给你搭建高并发、高可用、大数据框架的活呢,一条业务线总要成长吧,慢慢成熟了就要装修工来缝缝补补、美化美化,也就是CRUD的活。不能妄自菲薄CRUD Boy,我们是后端工程师。今天来指南下操作数据库之MyBatis框架。
132 3
我们后端程序员不是操作MyBatis的CRUD Boy
MybatisPlus-标准CRUD制作,新增boolean save(T t),删除 ~ delete(int id),修改 ~ update(T t),根据id查询,T getById....
MybatisPlus-标准CRUD制作,新增boolean save(T t),删除 ~ delete(int id),修改 ~ update(T t),根据id查询,T getById....
|
6月前
|
SQL XML Java
【MyBatis】 MyBatis框架下的高效数据操作:深入理解增删查改(CRUD)
【MyBatis】 MyBatis框架下的高效数据操作:深入理解增删查改(CRUD)
50 1