Mybatis由浅入深 - 02增删改查CRUD

2022-12-02 15:21:28 浏览数 (1)

这是Mybatis由浅入深的第2节,上文传送门:【Mybatis由浅入深 -01入门】

通过本文您将掌握:

  1. 基本的CRUD语句如何写?
  2. insert如何获得自增id值?
  3. #{}与${}的区别?
  4. @Param到底该怎么用? 什么时侯必须用,什么时侯可以不用
  5. SqlSessionFactory如何单例?

使用环境

以下为基础前置条件:请参考其它博文自行安装。

  • JDK:1.8
  • Maven: 3.6.3
  • Mysql: 5.7 安装教程

创建Mysql测试表

代码语言:javascript复制
CREATE TABLE `user`  (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `age` tinyint(1) UNSIGNED NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
insert into `user` VALUES (1,'天罡gg',18);

1、插入insert

1.1 接口方法

在UserMapper.java接口新增一个方法:

代码语言:javascript复制
	int insert(User user);

1.2. 对应的xml映射文件

在UserMapper.xml中插入insert节点,一般指定id(像使用雪花算法等 )的插入是这样的:

代码语言:javascript复制
	<insert id="insert" parameterType="com.tiangang.dao.po.User">
        insert into user (id, name, age)
        values (#{id}, #{name}, #{age})
    </insert>

如果不指定id, 插入后如何获得自增id值?

代码语言:javascript复制
    <insert id="insert" parameterType="com.tiangang.dao.po.User">
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
            SELECT LAST_INSERT_ID()
        </selectKey>
        insert into user (name, age)
        values (#{name}, #{age})
    </insert>

说明:现在一般公司都是遵循阿里规范,id是自增列,插入以后要拿到id,所以推荐做法就是在insert节点增加一个selectKey节点,在order=“after” 时将自增id值设置到keyProperty列。

面试常考点: #{} 是参数占位符, #{id}就是id的占位符,会解析为JDBC预编译语句, 可以防sql注入(就像使用JDBC的?一样); {} 是字符串替换,不防sql注入,在 SQL 语句中直接插入一个不转义的字符串,一般用在代替表名列名场景。 例如: 按列名排序 :select * from user order by {age}, 按任意列查询:select * from user where

1.3 单元测试

代码语言:javascript复制
	@Test
    public void insertTest() {
        // 1. 打开SqlSession
        SqlSession sqlSession = MyBatisManager.openSession();
        try {
            // 2. 得到UserMapper
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // 3. 执行insert
            User user = new User();
            user.setName("天罡666");
            user.setAge(28);
            int rows = mapper.insert(user);
            System.out.println("受影响行数:"   rows);
            System.out.println("新插入User:"   user);
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
            sqlSession.rollback();
        } finally {
            sqlSession.close();
        }
    }

插入成功截图:

2、修改update

2.1 接口方法

同理,在UserMapper.java接口新增一个方法:

代码语言:javascript复制
	int updateById(User user);

2.2 对应的xml映射文件

同理,在UserMapper.xml中插入update节点

代码语言:javascript复制
    <update id="updateById" parameterType="com.tiangang.dao.po.User">
        update user
        set name = #{name},
        age = #{age}
        where id = #{id}
    </update>

2.3 单元测试

代码语言:javascript复制
	@Test
    public void updateByIdTest() {
        // 1. 打开SqlSession
        SqlSession sqlSession = MyBatisManager.openSession();
        try {
            // 2. 得到UserMapper
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // 3. 执行update
            User user = new User();
            user.setId(2L);
            user.setName("天罡666");
            user.setAge(38);
            int rows = mapper.updateById(user);
            System.out.println("受影响行数:"   rows);
            System.out.println("修改后的User:"   user);
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
            sqlSession.rollback();
        } finally {
            sqlSession.close();
        }
    }

执行结果如下图:

3、删除delete

3.1 接口方法

同理,在UserMapper.java接口新增一个方法:

代码语言:javascript复制
    int deleteById(Long id);

3.2 对应的xml映射文件

同理,在UserMapper.xml中插入delete节点

代码语言:javascript复制
    <delete id="deleteById" parameterType="java.lang.Long">
        delete from user
        where id = #{id}
    </delete>

3.3 单元测试

代码语言:javascript复制
	@Test
    public void deleteByIdTest() {
        // 1. 打开SqlSession
        SqlSession sqlSession = MyBatisManager.openSession();
        try {
            // 2. 得到UserMapper
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // 3. 执行delete
            int rows = mapper.deleteById(2L);
            System.out.println("受影响行数:"   rows);
            sqlSession.commit();
        } catch (Exception e) {
            e.printStackTrace();
            sqlSession.rollback();
        } finally {
            sqlSession.close();
        }
    }

执行结果如下图:

4、查询select

为了演示需要,新插入User:User{id=3, name=‘天罡666’, age=28}

4.1 接口方法(5个必会的查询场景)

在UserMapper.java接口新增方法如下:

代码语言:javascript复制
    // 必会查询场景1:查询1个结果, 返回单个User
    User selectById(int id);
    // 必会查询场景2:查询N个结果, 返回结果List
    List<User> selectListByName(String name);
    // 必会查询场景3:根据N个参数(@Param指定参数名),查询N个结果,返回结果List
    List<User> selectListByNameAge(@Param("name") String name, @Param("gleAge") Integer gleAge);
    // 必会查询场景4:使用${} 进行任意列查询。另外,多个参数未指定@Param的使用
    List<User> selectByAnyOneColumn(String columnName, String symbol, String value);
    // 必会查询场景5:使用${} 进行order by
    List<User> selectAll(String orderBy);

4.2 对应的xml映射文件

在UserMapper.xml中插入5个select节点

代码语言:javascript复制
	<select id="selectById" resultType="com.tiangang.dao.po.User">
        select * from user where id = #{id}
    </select>

    <select id="selectListByName" resultType="com.tiangang.dao.po.User">
        select * from user
        where name like concat ('%', #{name},'%')
    </select>

    <select id="selectListByNameAge" resultType="com.tiangang.dao.po.User">
        select * from user
        where name like concat ('%', #{name},'%') and age>=#{gleAge}
    </select>

    <select id="selectByAnyOneColumn" resultType="com.tiangang.dao.po.User">
        select * from user
        where ${arg0} ${arg1} #{arg2}
    </select>

    <select id="selectAll" resultType="com.tiangang.dao.po.User">
        select * from user order by ${orderBy}
    </select>

4.3 单元测试

代码语言:javascript复制
    @Test
    public void selectByIdTest() {
        // 1. 打开SqlSession
        SqlSession sqlSession = MyBatisManager.openSession();
        try {
            // 2. 得到UserMapper
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // 3. 执行select
            User user = mapper.selectById(1);
            System.out.println(user);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

    @Test
    public void selectListByNameTest() {
        // 1. 打开SqlSession
        SqlSession sqlSession = MyBatisManager.openSession();
        try {
            // 2. 得到UserMapper
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // 3. 执行select
            List<User> userList = mapper.selectListByName("天罡");
            System.out.println(userList);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

    @Test
    public void selectListByNameAgeTest() {
        // 1. 打开SqlSession
        SqlSession sqlSession = MyBatisManager.openSession();
        try {
            // 2. 得到UserMapper
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // 3. 执行select
            List<User> userList = mapper.selectListByNameAge("天罡", 1);
            System.out.println(userList);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

    @Test
    public void selectByAnyOneColumnTest() {
        // 1. 打开SqlSession
        SqlSession sqlSession = MyBatisManager.openSession();
        try {
            // 2. 得到UserMapper
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // 3. 执行select
            List<User> userList = mapper.selectByAnyOneColumn("name", "=", "天罡666");
            System.out.println(userList);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

    @Test
    public void selectAllTest() {
        // 1. 打开SqlSession
        SqlSession sqlSession = MyBatisManager.openSession();
        try {
            // 2. 得到UserMapper
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // 3. 执行select
            List<User> userList = mapper.selectAll("age");
            System.out.println(userList);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

5、补充封装的MyBatisManager

细心的小伙伴可能已经发现多了一个MyBatisManager类,如果看了上文,就知道SqlSessionFactory应该是全局唯一的,所以我们将它封装到了MyBatisManager.getSqlSessionFactory方法中(使用单例模式),并向外提供了MyBatisManager.openSession,屏蔽了内部实现,使用方只需要每次调用openSession即可,你Get到了吗?

代码语言:javascript复制
public class MyBatisManager {

    private static volatile SqlSessionFactory sqlSessionFactory = null;

    public static SqlSessionFactory getSqlSessionFactory() {
        // double check 双重检查, 保证SqlSessionFactory全局只创建一次
        if (sqlSessionFactory == null) {
            synchronized (MyBatisManager.class) {
                if (sqlSessionFactory == null) {
                    String resource = "mybatis-config.xml";
                    try {
                        Reader reader = Resources.getResourceAsReader(resource);
                        sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return sqlSessionFactory;
    }

    public static SqlSession openSession() {
        return getSqlSessionFactory().openSession();
    }
}

6、本文全部源码

这节看似非常简单,实则非常考验基础,很多知识点相信有几年工作经验的人依然傻傻弄不清楚,

如有不到之处,敬请指正!

另外,源码中在单元测试类中CRUD做了简单的封装,新加了 UserMapperTest02Better.java,与UserMapperTest02.java测试功能一致,只是使用executeUserMapperMethod方法简化了代码,不作赘述,详细请见源码:https://download.csdn.net/download/scm_2008/86509214

0 人点赞