• MyBatis入门(二)MyBatis增删改查


    目录

    一.新增

    二.修改

    三.删除、根据Id查询

    1.删除用户

    2.根据Id查询

    四.模糊查询

    1.使用#定义参数

     2.使用$定义参数

    五.分页查询

    1.顺序传参

    2.@Param传参

    3.POJO传参

    4.Map传参

    六.聚合查询

    七.主键回填


    一.新增

    通过Navicat查看数据库,右键user表,点击设计表,可以看到表的各种设置

    可以看到user表的id列是自增的,也就是插入数据时不需要设置id字段!

    在接口文件里定义插入接口函数

     然后在UserMapper.xml中设置接口函数的映射

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <!DOCTYPE mapper
    3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    5. <!-- namespace设置映射的文件-->
    6. <mapper namespace="com.first.mapper.UserMapper">
    7. <!--
    8. id是方法名;
    9. resultType表示结果的对象,即列表的泛型;
    10. 查找用select标签 -->
    11. <select id="findAll" resultType="com.first.pojo.User">
    12. select * from user
    13. </select>
    14. <!-- 在values中传入对象的属性时就把属性放到#{}中-->
    15. <insert id="add" parameterType="com.first.pojo.User">
    16. insert into user (username,sex,address) values (#{username},#{sex},#{address})
    17. </insert>
    18. </mapper>

    不必在SqlMapConfig.xml中再配置了,因为之前已经配置过映射文件。

    在User.java中再添加一个三个参数的构造函数,因为插入时不用插入id字段

    1. public User(String username, String sex, String address) {
    2. this.username = username;
    3. this.sex = sex;
    4. this.address = address;
    5. }

    编写测试方法 ,在 测试类里添加如下方法:

    1. @Test
    2. public void testAdd() throws IOException {
    3. InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
    4. SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    5. SqlSessionFactory factory = builder.build(is);
    6. SqlSession session = factory.openSession();
    7. UserMapper userMapper = session.getMapper(UserMapper.class);
    8. User user=new User("塔姆","男","西安");
    9. userMapper.add(user);
    10. //提交事务,增删改都需要提交事务,否则数据库不会改变
    11. session.commit();
    12. //释放资源
    13. session.close();
    14. is.close();
    15. }
    注意:
    • 当接口方法的参数类型为POJO类型时,SQL语句中绑定参数时使用 #{POJO的属性名} 即可。
    • MyBatis事务默认手动提交,所以在执行完增删改方法后,需要手动调用SqlSession对象的事务提交方法,否则数据库将不发生改变。

    运行测试方法,也要看到数据库里插入成功!

    二.修改

    优化测试类
    我们发现 MyBatis 的测试方法在操作数据库前都需要获取代理对象,操作数据库后都需要释放资源,可以利用 Junit 前置后置方法 ,优化测试类代码。

    这样Junit就会自动执行获取代理对象和释放资源的方法。 新建一个TestUserMapper2.java测试类,利用前置和后置将公共部分取出,降低代码冗余度。

    1. package com.first.mapper;
    2. import com.first.pojo.User;
    3. import org.apache.ibatis.io.Resources;
    4. import org.apache.ibatis.session.SqlSession;
    5. import org.apache.ibatis.session.SqlSessionFactory;
    6. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    7. import org.junit.After;
    8. import org.junit.Before;
    9. import org.junit.Test;
    10. import java.io.IOException;
    11. import java.io.InputStream;
    12. public class TestUserMapper2 {
    13. //全局变量
    14. InputStream is=null;
    15. SqlSession session =null;
    16. UserMapper userMapper =null;
    17. //前置方法:测试类里的测试方法执行之前都会先执行前置方法
    18. @Before
    19. public void before() throws IOException {
    20. //(1)读取核心配置文件
    21. is= Resources.getResourceAsStream("SqlMapConfig.xml");
    22. //(2)创建SqlSessionFactoryBuilder对象
    23. SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    24. //(3)SqlSessionFactoryBuilder对象获取SqlSessionFactory对象
    25. SqlSessionFactory factory = builder.build(is);
    26. //(4)SqlSessionFactory对象获取SqlSession对象
    27. session = factory.openSession();
    28. //(5)SqlSession对象获取代理对象
    29. userMapper = session.getMapper(UserMapper.class);
    30. }
    31. 后置方法:测试类里的测试方法执行之后都会执行后置方法
    32. @After
    33. public void after() throws IOException {
    34. //(7)释放资源
    35. session.close();
    36. is.close();
    37. }
    38. }

    在UserMapper.java中添加接口函数:

    1. //修改数据
    2. void update(User user);

    在UserMapper.xml中注册映射:

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <!DOCTYPE mapper
    3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    5. <!-- namespace设置映射的文件-->
    6. <mapper namespace="com.first.mapper.UserMapper">
    7. <!--
    8. id是方法名;
    9. resultType表示结果的对象,即列表的泛型;
    10. 查找用select标签 -->
    11. <select id="findAll" resultType="com.first.pojo.User">
    12. select *
    13. from user
    14. </select>
    15. <!-- 在values中传入对象的属性时就把属性放到#{}中-->
    16. <!-- 参数类型是User对象-->
    17. <insert id="add" parameterType="com.first.pojo.User">
    18. insert into user (username, sex, address)
    19. values (#{username}, #{sex}, #{address})
    20. </insert>
    21. <update id="update" parameterType="com.first.pojo.User">
    22. update user
    23. set username=#{username},
    24. sex=#{sex},
    25. address=#{address}
    26. where id = #{id}
    27. </update>
    28. </mapper>

    编写测试函数:

    1. package com.first.mapper;
    2. import com.first.pojo.User;
    3. import org.apache.ibatis.io.Resources;
    4. import org.apache.ibatis.session.SqlSession;
    5. import org.apache.ibatis.session.SqlSessionFactory;
    6. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    7. import org.junit.After;
    8. import org.junit.Before;
    9. import org.junit.Test;
    10. import java.io.IOException;
    11. import java.io.InputStream;
    12. public class TestUserMapper2 {
    13. //全局变量
    14. InputStream is=null;
    15. SqlSession session =null;
    16. UserMapper userMapper =null;
    17. //前置方法:测试类里的测试方法执行之前都会先执行前置方法
    18. @Before
    19. public void before() throws IOException {
    20. //(1)读取核心配置文件
    21. is= Resources.getResourceAsStream("SqlMapConfig.xml");
    22. //(2)创建SqlSessionFactoryBuilder对象
    23. SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    24. //(3)SqlSessionFactoryBuilder对象获取SqlSessionFactory对象
    25. SqlSessionFactory factory = builder.build(is);
    26. //(4)SqlSessionFactory对象获取SqlSession对象
    27. session = factory.openSession();
    28. //(5)SqlSession对象获取代理对象
    29. userMapper = session.getMapper(UserMapper.class);
    30. }
    31. 后置方法:测试类里的测试方法执行之后都会执行后置方法
    32. @After
    33. public void after() throws IOException {
    34. //(7)释放资源
    35. session.close();
    36. is.close();
    37. }
    38. @Test
    39. public void testUpdate(){
    40. User user = new User(7,"吉米","女","深圳");
    41. userMapper.update(user);
    42. session.commit();
    43. }
    44. }

    运行:

    看到数据库已经更新

    三.删除、根据Id查询

    1.删除用户

    在UserMapper.java中添加接口函数:

    1. //删除用户
    2. void delete(int userId);

     在UserMapper.xml中配置映射:

    1. <delete id="delete" parameterType="int">
    2. delete
    3. from user
    4. where id = #{sbID}
    5. </delete>
    注:当方法的参数类型是简单数据类型时, #{} 中可以写任意名称 ,就像形参那样,叫啥都行,比如我这里叫了sbID
    简单数据类型:基本数据类型、字符串等
    编写测试方法
    1. @Test
    2. public void testDelete(){
    3. userMapper.delete(7);
    4. session.commit();
    5. }

    运行发现果然删除成功!

    2.根据Id查询

    在UserMapper.java中添加接口函数:

    1. //根据id查找用户
    2. User findById(int userId);

     在UserMapper.xml中配置映射:

    参数是用户的id,是int类型(故而参数名随便起了个userId),返回的结果是一个用户对象,类型是User

    1. <select id="findById" parameterType="int" resultType="com.first.pojo.User">
    2. select * from user where id=#{userId}
    3. </select>

     编写测试方法

    1. @Test
    2. public void testFindById(){
    3. //查询操作没有修改数据库,不用提交事务
    4. User user = userMapper.findById(1);
    5. System.out.println(user);
    6. }

    输出:

    User{id=1, username='小热', sex='男', address='北京'}

    四.模糊查询

    1.使用#定义参数

    在UserMapper.java中添加接口函数(持久层接口添加方法):

    1. //根据用户名进行模糊查询
    2. List<User> findByUsernameLike(String username);

     在UserMapper.xml中配置映射: (即映射文件添加标签

    1. <!-- 注意parameterType是小写的string,另一种写法是java.lang.String-->
    2. <select id="findByUsernameLike" parameterType="string" resultType="com.first.pojo.User">
    3. select * from user where username like #{username}
    4. </select>

     编写测试方法

    1. @Test
    2. public void testFindByUsernameLike(){
    3. List<User> users=userMapper.findByUsernameLike("%小%");
    4. users.forEach(System.out::println);
    5. }

    运行:

    名字里带小的都能查询出来

    1. User{id=1, username='小热', sex='男', address='北京'}
    2. User{id=2, username='小巴', sex='男', address='上海'}
    3. User{id=3, username='小赵', sex='女', address='广州'}
    4. User{id=4, username='小迪', sex='男', address='北京'}
    5. User{id=5, username='小丽', sex='男', address='太原'}
    我们看到在映射文件中, parameterType 的值为 string 而没有写 java.lang.String ,这是为什么呢?
    参数 / 返回值类型为基本数据类型 / 包装类 /String 等类型时,我们可以写全类名,也可以写别名。

     

     2.使用$定义参数

    模糊查询如果不想在调用方法时参数加 % ,可以使用拼接参数的方式设置 Sql
    1. <select id="findByUsernameLike" parameterType="string" resultType="com.first.pojo.User">
    2. select * from user where username like '%${value}%'
    3. </select>

    测试方法写法如下:

    1. @Test
    2. public void testFindByUsernameLike(){
    3. List<User> users=userMapper.findByUsernameLike("小");
    4. users.forEach(System.out::println);
    5. }

    运行测试方法,发现运行成功,名字里带“小”的用户信息都被查出!

    #$ 的区别:  
    1. 1 #表示sql模板的占位符,$表示将字符串拼接到sql模板中。
    2. 2 #可以防止sql注入(相当于学JDBC时的PreparedStatement),一般能用#就不用$(相当于学JDBC时的Statement)。
    3. 3 ${}内部的参数名必须写value
    使用 <bind> 定义参数
    如果使用 # 还不想在调用方法的参数中添加 % ,可以使用 <bind> <bind> 允许我们在 Sql 语句以外创建一个变量,并可以将其绑定到当 前的 Sql 语句中。用法如下:
    1. <select id="findByUsernameLike" parameterType="string" resultType="com.first.pojo.User">
    2. <bind name="likeName" value="'%'+username+'%'"/>
    3. select * from user where username like #{likeName}
    4. </select>

    测试方法写法如下: 

    1. @Test
    2. public void testFindByUsernameLike(){
    3. List<User> users=userMapper.findByUsernameLike("小");
    4. users.forEach(System.out::println);
    5. }

     运行结果和上面一致!

    五.分页查询

    分页查询时, Sql 语句使用 limit 关键字,需要传入开始索引和每页条数两个参数。 MyBatis 的多参数处理有以下方式:

    1.顺序传参

    Sql 中的参数使用 arg0 arg1... param1 param2... 表示参数的顺序。 此方法可读性较低,在开发中不建议使用。
    持久层接口方法 :
    1. //下面的注释先把接口函数写完,然后在函数上一行打出/**然后回车就出来了
    2. /**
    3. *
    4. * @param startIndex 开始索引
    5. * @param pageSize 每页条数
    6. * @return
    7. */
    8. List<User> findPage(int startIndex,int pageSize);
    映射文件 :
    1. <!--多个参数时就没必要设置parameterType,因为参数类型可能不同-->
    2. <!-- 其中arg0,arg1也可以换成param1和param2-->
    3. <select id="findPage" resultType="com.first.pojo.User">
    4. select * from user limit #{arg0},#{arg1}
    5. </select>

    测试类 :

    1. @Test
    2. public void testFindPage(){
    3. List<User> users = userMapper.findPage(0, 3);
    4. users.forEach(System.out::println);
    5. }

    运行测试方法:

    1. User{id=1, username='小热', sex='男', address='北京'}
    2. User{id=2, username='小巴', sex='男', address='上海'}
    3. User{id=3, username='小赵', sex='女', address='广州'}

    2.@Param传参

    在接口方法的参数列表中通过 @Param 定义参数名称,在 Sql 语句中通过注解中所定义的参数名称指定参数位置。 此方式参数比较直观的,推荐使用。
    1
    持久层接口方法 :
    1. /**
    2. *
    3. * @param startIndex 开始索引
    4. * @param pageSize 每页条数
    5. * @return
    6. */
    7. //推荐注解名和参数名一致,这样可读性高
    8. List<User> findPage1(@Param("startIndex") int startIndex, @Param("pageSize") int pageSize);
    映射文件 :
    1. <!-- 直接传入参数对应的注解名-->
    2. <select id="findPage1" resultType="com.first.pojo.User">
    3. select * from user limit #{startIndex},#{pageSize}
    4. </select>
    测试类 :
    1. @Test
    2. public void testFindPage1(){
    3. List<User> users = userMapper.findPage1(3, 3);
    4. users.forEach(System.out::println);
    5. }

    运行测试方法:

    1. User{id=4, username='小迪', sex='男', address='北京'}
    2. User{id=5, username='小丽', sex='男', address='太原'}
    3. User{id=6, username='本本', sex='男', address='西安'}

    3.POJO传参

    自定义 POJO 类,该类的属性就是要传递的参数,在 SQL 语句中绑定参数时使用 POJO 的属性名作为参数名即可。 此方式推荐使用。
    1
    自定义 POJO :
    在src/main/java/com/first/pojo/下创建PageQuery类
    1. package com.first.pojo;
    2. public class PageQuery {
    3. private int startIndex;
    4. private int pageSize;
    5. public PageQuery() {
    6. }
    7. public PageQuery(int startIndex, int pageSize) {
    8. this.startIndex = startIndex;
    9. this.pageSize = pageSize;
    10. }
    11. public int getStartIndex() {
    12. return startIndex;
    13. }
    14. public void setStartIndex(int startIndex) {
    15. this.startIndex = startIndex;
    16. }
    17. public int getPageSize() {
    18. return pageSize;
    19. }
    20. public void setPageSize(int pageSize) {
    21. this.pageSize = pageSize;
    22. }
    23. }
    持久层接口方法 :
    1. /**
    2. * 分页查询
    3. */
    4. //参数是一个类对象
    5. List<User> findPage2(PageQuery pageQuery);
    映射文件:
    1. <!-- pojo传参-->
    2. <select id="findPage2" resultType="com.first.pojo.User" parameterType="com.first.pojo.PageQuery">
    3. select * from user limit #{startIndex},#{pageSize}
    4. </select>

    测试函数:

    1. @Test
    2. public void testFindPage2(){
    3. PageQuery pageQuery=new PageQuery(3,3);
    4. List<User> users = userMapper.findPage2(pageQuery);
    5. users.forEach(System.out::println);
    6. }

    运行:

    1. User{id=4, username='小迪', sex='男', address='北京'}
    2. User{id=5, username='小丽', sex='男', address='太原'}
    3. User{id=6, username='本本', sex='男', address='西安'}

    4.Map传参

    如果不想自定义 POJO ,可以使用 Map 作为传递参数的载体,在 SQL语句中绑定参数时使用 Map Key 作为参数名即可。 此方法推荐使用。
    1
    持久层接口方法:
    1. //参数是一个Map对象
    2. List<User> findPage3(Map<String,Object> params);
    映射文件
    1. <select id="findPage3" resultType="com.first.pojo.User" parameterType="map">
    2. select * from user limit #{startIndex},#{pageSize}
    3. </select>

    测试函数:

    1. @Test
    2. public void testFindPage3(){
    3. Map<String,Object> params = new HashMap();
    4. params.put("startIndex",0);
    5. params.put("pageSize",4);
    6. List<User> users = userMapper.findPage3(params);
    7. users.forEach(System.out::println);
    8. }

    运行:

    1. User{id=1, username='小热', sex='男', address='北京'}
    2. User{id=2, username='小巴', sex='男', address='上海'}
    3. User{id=3, username='小赵', sex='女', address='广州'}
    4. User{id=4, username='小迪', sex='男', address='北京'}

    在MyBatis中使用Map传参,Map键的类型为: String

    六.聚合查询

    举例:查询用户总数

    持久层接口方法:
    int findCount();
    映射文件
    1. <select id="findCount" resultType="int">
    2.   select count(id) from user
    3. </select>
    测试方法:
    1. @Test
    2. public void testFindCount(){
    3. System.out.println(userMapper.findCount());
    4. }

    运行输出:

    7

    七.主键回填

    有时我们需要获取新插入数据的主键值。如果数据库中主键是自增的,这时我们就需要使用 MyBatis 的主键回填功能。
    1
    持久层接口方法:
    void add2(User user);
    映射文件:
    1. <insert id="add2" parameterType="com.first.pojo.User">
    2. <!-- keyProperty:主键属性名,keyColumn:主键列名,resultType:主键类型,
    3. order:执行时机,AFTER是代表在插入之后执行 -->
    4. <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
    5. SELECT LAST_INSERT_ID();
    6. </selectKey>
    7. insert into user(username,sex,address)
    8. values(#{username},#{sex},#{address})
    9. </insert>
    SELECT LAST_INSERT_ID():查询刚刚插入的记录的主键值,只适用于自增主键,且必须和insert语句一起执行。

    测试方法:

    主键回填即自动递增的逐渐不止体现在数据库中,咱们new的user对象起初并没有赋id值,所以主键回填就是把自动生成的主键回填到user对象的id值上!

    1. @Test
    2. public void testAdd2(){
    3. User user = new User("丽颖", "女", "南京");
    4. //如果换成最开始写的add()函数,那么返回值是0
    5. userMapper.add2(user);
    6. session.commit();
    7. System.out.println(user.getId());
    8. }

    运行:

    9


    到此为止的项目结构如下:

  • 相关阅读:
    找视频剪辑素材就上这6个网站 优漫教育
    git 的行结束符
    vulnhub靶场之HACK ME PLEASE
    DES & 3DES 简介 以及 C# 和 js 实现【加密知多少系列】
    前端工程化(editorconfig+ESLint+Prettier+StyleLint+Husky、Commitlint)
    创建多维时间序列DataFrame并显示前(后)指定天数的数据的df.last()方法
    记录:微信小程序 数据请求 GET请求和POST请求
    多快递统一管理教程
    IntelliJ IDEA(Windows 版)的所有快捷键
    Xmake v2.8.3 发布,改进 Wasm 并支持 Xmake 源码调试
  • 原文地址:https://blog.csdn.net/weixin_44593822/article/details/124945024