MyBatis

Mybatis上手教程–增删改查

一 增删改查说明

前面的例子中「Mybatis上手教程–面向接口编程」,我们通过定义EmployeeMapper这个接口,并定义了一个查询方法:

package com.knockatdatabase.dao;

import com.knockatdatabase.Employee;

/**
* @Author:asher
* @Date:2021/10/2 10:24
* @Description:com.knockatdatabase.dao
* @Version:1.0
*/
public interface EmployeeMapper {
   Employee getEmployeeById(Integer id);
}

然后,在SQL mapper文件里把namespace映射到该接口的全类名,SQL id映射该接口的方法名,最后在测试类中获取SqlSession对象之后,调用getMapper()方法,并通过传入该参数的实现类的对象,进而通过反射的方式,调用该接口中的方法getEmployeeById(),并最终通过将接口和SQL mapper文件绑定的方式,来实现Java代码和SQL解耦,并最终实现的。

二 添加方法addEmployee()的流程

1 在接口中添加addEmployee()的方法
package com.knockatdatabase.dao;

import com.knockatdatabase.Employee;

/**
* @Author:asher
* @Date:2021/10/2 10:24
* @Description:com.knockatdatabase.dao
* @Version:1.0
*/
public interface EmployeeMapper {
   Employee getEmployeeById(Integer id);

   void insertEmployee(Employee employee);
}

方法返回值是void,参数是一个Employee对象。

2 在SQL mapper文件中添加映射SQL
<?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.knockatdatabase.dao.EmployeeMapper">
<insert id="insertEmployee" parameterType="com.knockatdatabase.Employee">
  insert into tbl_employee(last_name,gender,email)
  values (#{lastName},#{gender},#{mail})
</insert>
<select id="getEmployeeById" resultType="com.knockatdatabase.Employee">
  select id,last_name ,gender,email as mail from tbl_employee where id = #{id}
 </select>
</mapper>

其中,由于后端MySQL数据库中设定的id是自增主键,所以,这里的SQL中,可以直接忽略id字段。同时values()中,直接写#{},在大括号里直接写实体类Employee里的成员属性名即可。

问题,为什么直接写成员变量即可呢?Mybatis是怎么读取到该成员变量的值的呢?

3测试类中测试
@Test
   public void testInsert() {
       String resource = "mybatis-config.xml";
       Employee employee = new Employee(null, "Huang", "男", "hensi163@163.com");
       SqlSession sqlSession = null;
       try {
           InputStream inputStream = Resources.getResourceAsStream(resource);
           SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
           sqlSession = sqlSessionFactory.openSession();
           EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
           mapper.insertEmployee(employee);
           sqlSession.commit();
      } catch (IOException e) {
           e.printStackTrace();
      }
       finally {
           sqlSession.close();
      }
  }

思路还是一样的,先读取配置文件,通过SqlSessionFactoryBuilder获取一个SqlSessionFactory的对象,然后调用openSession()方法,得到一个SqlSession的对象,注意:此时方法的返回值有2种类型,一种是autocommit的,一种是非自动提交事务的,那么后面执行完事务之后,就要显示的手工提交事务。

同时,该测试方法中,先new 一个Employee类的对象,此时要在Employee的Java bean中,添加无参、有参构造方法。且,此处的id赋值为NULL,因为id要通过MySQL数据库自身的auto increment来生成。

后面,调用mapper.insertEmployee(employee);把它当做参数传递进去。

最后,不要忘记关闭SqlSession对象。

4 验证测试结果
[mysql@ppasdev ~]$ mysql  -umybatis_project -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2576
Server version: 5.6.32-log MySQL Community Server (GPL)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use mybatis_project;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from tbl_employee;
+----+-----------+--------+-------------------+
| id | last_name | gender | email             |
+----+-----------+--------+-------------------+
|  1 | Huang     | 1      | 3dian14@gmail.com |
|  2 | Huang     | ?      | hensi163@163.com  |
+----+-----------+--------+-------------------+
2 rows in set (0.00 sec)

mysql>

可以看到,数据库中的确多了一条记录,但是有个小问题,性别列呈现的是乱码。

5 解决中文乱码问题

解决该问题的方法,可以是在数据源的配置里面,加上“?useUnicode=true&characterEncoding=utf-8“。

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://172.16.11.35:3306/mybatis_project?useUnicode=true&characterEncoding=utf-8
jdbc.username=mybatis_project
jdbc.password=mybatis_project

如果是直接配置在mybatis-config.xml文件里的话,则需要转义一下&字符,用这种方式:?useUnicode=true&characterEncoding=utf-8

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://172.16.11.35:3306/mybatis_project?useUnicode=true&amp;characterEncoding=utf-8
jdbc.username=mybatis_project
jdbc.password=mybatis_project

重新测试,就不再有乱码了:

mysql> select * from tbl_employee;
+----+-----------+--------+-------------------+
| id | last_name | gender | email             |
+----+-----------+--------+-------------------+
|  1 | Huang     | 1      | 3dian14@gmail.com |
|  2 | Huang     | ?      | hensi163@163.com  |
|  3 | Huang     | 男     | hensi163@163.com  |
+----+-----------+--------+-------------------+
3 rows in set (0.00 sec)

mysql>
6 补充Mybatis使用自增主键

Mybatis支持对MySQL自增主键,就是在SQL mapper文件中,这样配置额外的2个属性:useGeneratedKeys=”true” keyProperty=”id”,表示支持自增主键,同时把这个自增主键映射的Java bean的id字段上。

<?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.knockatdatabase.dao.EmployeeMapper">
<insert id="insertEmployee" parameterType="com.knockatdatabase.Employee" useGeneratedKeys="true" keyProperty="id">
  insert into tbl_employee(last_name,gender,email)
  values (#{lastName},#{gender},#{mail})
</insert>
<select id="getEmployeeById" resultType="com.knockatdatabase.Employee">
  select id,last_name ,gender,email as mail from tbl_employee where id = #{id}
 </select>
</mapper>

这样的话,就可以在Java测试类的代码中,通过Java代码获取到MySQL自动帮我们生成的自增主键值:System.out.println(employee.getId());。

三更新方法流程

1 接口中添加更新方法

方法返回值为Boolean。

package com.knockatdatabase.dao;

import com.knockatdatabase.Employee;

/**
* @Author:asher
* @Date:2021/10/2 10:24
* @Description:com.knockatdatabase.dao
* @Version:1.0
*/
public interface EmployeeMapper {
   Employee getEmployeeById(Integer id);

   void insertEmployee(Employee employee);

   Boolean updateEmployee(Employee employee);
}
2 SQL mapper文件中添加映射
<?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.knockatdatabase.dao.EmployeeMapper">
<insert id="insertEmployee" parameterType="com.knockatdatabase.Employee">
  insert into tbl_employee(last_name,gender,email)
  values (#{lastName},#{gender},#{mail})
</insert>
   <update id="updateEmployee">
      update tbl_employee set last_name=#{lastName},gender=#{gender},email=#{mail}
      where id=#{id}
   </update>
   <select id="getEmployeeById" resultType="com.knockatdatabase.Employee">
  select id,last_name ,gender,email as mail from tbl_employee where id = #{id}
 </select>
</mapper>
3 编写测试方法
@Test
public void testUpdate() {
   Employee employee = new Employee(1, "黄伟", "男", "huangwei@knockatdatabase.com");
   SqlSession sqlSession = null;
   try{
       String resource = "mybatis-config.xml";
       InputStream inputStream = Resources.getResourceAsStream(resource);
       SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
       sqlSession = sqlSessionFactory.openSession();
       EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
       Boolean updateEmployee = mapper.updateEmployee(employee);
       System.out.println("Update successfully ? "+updateEmployee);
       sqlSession.commit();
  } catch (IOException e) {
       e.printStackTrace();
  } finally {
       sqlSession.close();
  }
}
//执行结果:
Update successfully ? true
4 数据库验证
mysql> select * from tbl_employee;
+----+-----------+--------+------------------------------+
| id | last_name | gender | email                        |
+----+-----------+--------+------------------------------+
|  1 | 黄伟      | 男     | huangwei@knockatdatabase.com |
|  2 | Huang     | ?      | hensi163@163.com             |
|  3 | Huang     | 男     | hensi163@163.com             |
+----+-----------+--------+------------------------------+
3 rows in set (0.00 sec)

mysql>

可以看到,前面添加的那条记录,已经被更新为这条新new出来的对象。

这就是用一个对象去更新另外一个对象的场景。说实话,我还是不太明白或者不能足够理解这种场景。回头找同事问问。

四删除方法流程

1接口中定义删除方法

返回值为Boolean:

package com.knockatdatabase.dao;

import com.knockatdatabase.Employee;

/**
* @Author:asher
* @Date:2021/10/2 10:24
* @Description:com.knockatdatabase.dao
* @Version:1.0
*/
public interface EmployeeMapper {
   Employee getEmployeeById(Integer id);

   void insertEmployee(Employee employee);

   Boolean updateEmployee(Employee employee);

   Boolean deleteEmployeeById(Integer id);
}
2 SQL mapper文件添加映射
<?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.knockatdatabase.dao.EmployeeMapper">
<insert id="insertEmployee" parameterType="com.knockatdatabase.Employee">
  insert into tbl_employee(last_name,gender,email)
  values (#{lastName},#{gender},#{mail})
</insert>
   <update id="updateEmployee">
      update tbl_employee set last_name=#{lastName},gender=#{gender},email=#{mail}
      where id=#{id}
   </update>
   <delete id="deleteEmployeeById">
      delete from tbl_employee where id=#{id}
   </delete>
   <select id="getEmployeeById" resultType="com.knockatdatabase.Employee">
  select id,last_name ,gender,email as mail from tbl_employee where id = #{id}
 </select>
</mapper>
3 测试方法
@Test
public void testDelete() {
   SqlSession sqlSession = null;
   try{
       String resource = "mybatis-config.xml";
       InputStream inputStream = Resources.getResourceAsStream(resource);
       SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
       sqlSession = sqlSessionFactory.openSession();
       EmployeeMapper mapper = (EmployeeMapper) sqlSession.getMapper(Class.forName("com.knockatdatabase.dao.EmployeeMapper"));
       Boolean deleteEmployeeById = mapper.deleteEmployeeById(3);
       System.out.println("删除成功吗? "+deleteEmployeeById);
       sqlSession.commit();
  } catch (IOException | ClassNotFoundException e) {
       e.printStackTrace();
  }finally {
       sqlSession.close();
  }
}
//执行结果:
删除成功吗? true
4 数据库验证
mysql> select * from tbl_employee;
+----+-----------+--------+------------------------------+
| id | last_name | gender | email                        |
+----+-----------+--------+------------------------------+
|  1 | 黄伟      | 男     | huangwei@knockatdatabase.com |
|  2 | Huang     | ?      | hensi163@163.com             |
+----+-----------+--------+------------------------------+
2 rows in set (0.00 sec)

mysql>

五小结

  • 通过基础的增删改查来联系使用mybatis和数据库交互;
  • 体会到定义接口,定义方法,将接口和SQL mapper绑定在一起使用;
  • 体会如何通过反射类获取接口的实现类的对象,最后再通过这个对象来调用接口中的方法;而接口中的方法又和mybatis 的SQL mapper文件绑定,进而执行SQL语句,最后和数据库完成交互操作。
  • 但是,也有几个小问题,回头得跟同事多讨论,多强化自己在这方面的欠缺的知识,问题就是文章中的加黄颜色的部分;

留言