广告位联系
返回顶部
分享到

MyBatis实现CRUD的代码

java 来源:互联网 作者:佚名 发布时间:2024-12-09 22:44:22 人浏览
摘要

准备工作 创建module(Maven的普通Java模块):mybatis-002-crud pom.xml 打包方式jar 依赖: mybatis依赖 mysql驱动依赖 junit依赖 logback依赖 mybatis-config.xml放在类的根路径下 CarMapper.xml放在类的根路径下 lo

准备工作

创建module(Maven的普通Java模块):mybatis-002-crud

pom.xml

  • 打包方式jar
  • 依赖:
    • mybatis依赖
    • mysql驱动依赖
    • junit依赖
    • logback依赖
  • mybatis-config.xml放在类的根路径下
  • CarMapper.xml放在类的根路径下
  • logback.xml放在类的根路径下
  • 提供com.study.mybatis.utils.SqlSessionUtil工具类
  • 创建测试用例:com.study.mybatis.CarMapperTest

1 insert(Create)

分析以下SQL映射文件中SQL语句存在的问题

1

2

3

4

5

6

7

8

9

10

11

<?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">

 

<!--namespace先随便写-->

<mapper namespace="car">

    <insert id="insertCar">

        insert into t_car(car_num, brand, guide_price, produce_time, car_type) values ('103', '奔驰E300L', 50.3, '2022-01-01', '燃油车')

    </insert>

</mapper>

存在的问题是:SQL语句中的值不应该写死,值应该是用户提供的。之前的JDBC代码是这样写的:

1

2

3

4

5

6

7

8

9

// JDBC中使用 ? 作为占位符。那么MyBatis中会使用什么作为占位符呢?

String sql = "insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(?,?,?,?,?)";

// ......

// 给 ? 传值。那么MyBatis中应该怎么传值呢?

ps.setString(1,"103");

ps.setString(2,"奔驰E300L");

ps.setDouble(3,50.3);

ps.setString(4,"2022-01-01");

ps.setString(5,"燃油车");

在MyBatis中可以这样做:
在Java程序中,将数据放到Map集合中在sql语句中使用 #{map集合的key} 来完成传值,#{} 等同于JDBC中的 ? ,#{}就是占位符Java程序这样写:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

package com.study.mybatis;

 

import com.study.mybatis.utils.SqlSessionUtil;

import org.apache.ibatis.session.SqlSession;

import org.junit.Test;

 

import java.util.HashMap;

import java.util.Map;

 

/**

 * 测试MyBatis的CRUD

 * @author sqnugy

 * @version 1.0

 * @since 1.0

 */

public class CarMapperTest {

    @Test

    public void testInsertCar(){

        // 准备数据

        Map<String, Object> map = new HashMap<>();

        map.put("k1", "103");

        map.put("k2", "奔驰E300L");

        map.put("k3", 50.3);

        map.put("k4", "2020-10-01");

        map.put("k5", "燃油车");

        // 获取SqlSession对象

        SqlSession sqlSession = SqlSessionUtil.openSession();

        // 执行SQL语句(使用map集合给sql语句传递数据)

        int count = sqlSession.insert("insertCar", map);

        System.out.println("插入了几条记录:" + count);

    }

}

SQL语句这样写:

1

2

3

4

5

6

7

8

9

10

11

<?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">

 

<!--namespace先随便写-->

<mapper namespace="car">

    <insert id="insertCar">

        insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(#{k1},#{k2},#{k3},#{k4},#{k5})

    </insert>

</mapper>

**#{} 的里面必须填写map集合的key,不能随便写。**运行测试程序,查看数据库:

如果#{}里写的是map集合中不存在的key会有什么问题?

1

2

3

4

5

6

7

8

9

10

<?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="car">

    <insert id="insertCar">

        insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(#{kk},#{k2},#{k3},#{k4},#{k5})

    </insert>

</mapper>

运行程序:

通过测试,看到程序并没有报错。正常执行。不过 #{kk} 的写法导致无法获取到map集合中的数据,最终导致数据库表car_num插入了NULL。
在以上sql语句中,可以看到#{k1} #{k2} #{k3} #{k4} #{k5}的可读性太差,为了增强可读性,我们可以将Java程序做如下修改:

1

2

3

4

5

6

7

Map<String, Object> map = new HashMap<>();

// 让key的可读性增强

map.put("carNum", "103");

map.put("brand", "奔驰E300L");

map.put("guidePrice", 50.3);

map.put("produceTime", "2020-10-01");

map.put("carType", "燃油车");

SQL语句做如下修改,这样可以增强程序的可读性:

1

2

3

4

5

6

7

8

9

<?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="car">

    <insert id="insertCar">

        insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})

    </insert>

</mapper>

运行程序,查看数据库表:

使用Map集合可以传参,那使用pojo(简单普通的java对象)可以完成传参吗?测试一下:

  • 第一步:定义一个pojo类Car,提供相关属性。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

package com.study.mybatis.pojo;

 

/**

 * POJOs,简单普通的Java对象。封装数据用的。

 * @author sqnugy

 * @version 1.0

 * @since 1.0

 */

public class Car {

    private Long id;

    private String carNum;

    private String brand;

    private Double guidePrice;

    private String produceTime;

    private String carType;

 

    @Override

    public String toString() {

        return "Car{" +

                "id=" + id +

                ", carNum='" + carNum + '\'' +

                ", brand='" + brand + '\'' +

                ", guidePrice=" + guidePrice +

                ", produceTime='" + produceTime + '\'' +

                ", carType='" + carType + '\'' +

                '}';

    }

 

    public Car() {

    }

 

    public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {

        this.id = id;

        this.carNum = carNum;

        this.brand = brand;

        this.guidePrice = guidePrice;

        this.produceTime = produceTime;

        this.carType = carType;

    }

 

    public Long getId() {

        return id;

    }

 

    public void setId(Long id) {

        this.id = id;

    }

 

    public String getCarNum() {

        return carNum;

    }

 

    public void setCarNum(String carNum) {

        this.carNum = carNum;

    }

 

    public String getBrand() {

        return brand;

    }

 

    public void setBrand(String brand) {

        this.brand = brand;

    }

 

    public Double getGuidePrice() {

        return guidePrice;

    }

 

    public void setGuidePrice(Double guidePrice) {

        this.guidePrice = guidePrice;

    }

 

    public String getProduceTime() {

        return produceTime;

    }

 

    public void setProduceTime(String produceTime) {

        this.produceTime = produceTime;

    }

 

    public String getCarType() {

        return carType;

    }

 

    public void setCarType(String carType) {

        this.carType = carType;

    }

}

  • 第二步:Java程序

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

@Test

public void testInsertCarByPOJO(){

    // 创建POJO,封装数据

    Car car = new Car();

    car.setCarNum("103");

    car.setBrand("奔驰C200");

    car.setGuidePrice(33.23);

    car.setProduceTime("2020-10-11");

    car.setCarType("燃油车");

    // 获取SqlSession对象

    SqlSession sqlSession = SqlSessionUtil.openSession();

    // 执行SQL,传数据

    int count = sqlSession.insert("insertCarByPOJO", car);

    System.out.println("插入了几条记录" + count);

}

  • 第三步:SQL语句

1

2

3

4

<insert id="insertCarByPOJO">

  <!--#{} 里写的是POJO的属性名-->

  insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})

</insert>

  • 运行程序,查看数据库表:

#{} 里写的是POJO的属性名,如果写成其他的会有问题吗?

1

2

3

<insert id="insertCarByPOJO">

  insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(#{a},#{brand},#{guidePrice},#{produceTime},#{carType})

</insert>

运行程序,出现了以下异常:

错误信息中描述:在Car类中没有找到a属性的getter方法。

修改POJO类Car的代码,只将getCarNum()方法名修改为getA(),其他代码不变,如下:

再运行程序,查看数据库表中数据:

经过测试得出结论:

如果采用map集合传参,#{} 里写的是map集合的key,如果key不存在不会报错,数据库表中会插入NULL。

如果采用POJO传参,#{} 里写的是get方法的方法名去掉get之后将剩下的单词首字母变小写(例如:getAge对应的是#{age},getUserName对应的是#{userName}),如果这样的get方法不存在会报错。

注意:其实传参数的时候有一个属性parameterType,这个属性用来指定传参的数据类型,不过这个属性是可以省略的

1

2

3

4

5

6

7

<insert id="insertCar" parameterType="java.util.Map">

  insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})

</insert>

 

<insert id="insertCarByPOJO" parameterType="com.study.mybatis.pojo.Car">

  insert into t_car(car_num,brand,guide_price,produce_time,car_type) values(#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})

</insert>

2 delete(Delete)

需求:根据car_num进行删除。
SQL语句这样写:

1

2

3

<delete id="deleteByCarNum">

  delete from t_car where car_num = #{SuiBianXie}

</delete>

Java程序这样写:

1

2

3

4

5

6

7

8

@Test

public void testDeleteByCarNum(){

    // 获取SqlSession对象

    SqlSession sqlSession = SqlSessionUtil.openSession();

    // 执行SQL语句

    int count = sqlSession.delete("deleteByCarNum", "102");

    System.out.println("删除了几条记录:" + count);

}

运行结果:

注意:当占位符只有一个的时候,${} 里面的内容可以随便写。

3 update(Update)

需求:修改id=34的Car信息,car_num为102,brand为比亚迪汉,guide_price为30.23,produce_time为2018-09-10,car_type为电车修改前:

SQL语句如下:

1

2

3

4

5

6

7

<update id="updateCarByPOJO">

  update t_car set

    car_num = #{carNum}, brand = #{brand},

    guide_price = #{guidePrice}, produce_time = #{produceTime},

    car_type = #{carType}

  where id = #{id}

</update>

Java代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

@Test

public void testUpdateCarByPOJO(){

    // 准备数据

    Car car = new Car();

    car.setId(34L);

    car.setCarNum("102");

    car.setBrand("比亚迪汉");

    car.setGuidePrice(30.23);

    car.setProduceTime("2018-09-10");

    car.setCarType("电车");

    // 获取SqlSession对象

    SqlSession sqlSession = SqlSessionUtil.openSession();

    // 执行SQL语句

    int count = sqlSession.update("updateCarByPOJO", car);

    System.out.println("更新了几条记录:" + count);

}

运行结果:

0670B92C-E654-49a7-839C-814850A4D79A.png

当然了,如果使用map传数据也是可以的。

4 select(Retrieve)

select语句和其它语句不同的是:查询会有一个结果集。来看mybatis是怎么处理结果集的!!!

查询一条数据

需求:查询id为1的Car信息
SQL语句如下:

1

2

3

<select id="selectCarById">

  select * from t_car where id = #{id}

</select>

Java程序如下:

1

2

3

4

5

6

7

8

@Test

public void testSelectCarById(){

    // 获取SqlSession对象

    SqlSession sqlSession = SqlSessionUtil.openSession();

    // 执行SQL语句

    Object car = sqlSession.selectOne("selectCarById", 1);

    System.out.println(car);

}

运行结果如下:

### Error querying database.  Cause: org.apache.ibatis.executor.ExecutorException: 
    A query was run and no Result Maps were found for the Mapped Statement 'car.selectCarById'.  【翻译】:对于一个查询语句来说,没有找到查询的结果映射。
    It's likely that neither a Result Type nor a Result Map was specified.                         【翻译】:很可能既没有指定结果类型,也没有指定结果映射。

以上的异常大致的意思是:对于一个查询语句来说,你需要指定它的“结果类型”或者“结果映射”。

所以说,你想让mybatis查询之后返回一个Java对象的话,至少你要告诉mybatis返回一个什么类型的Java对象,可以在<select>标签中添加resultType属性,用来指定查询要转换类型:

1

2

3

<select id="selectCarById" resultType="com.study.mybatis.pojo.Car">

  select * from t_car where id = #{id}

</select>

运行结果:

运行后之前的异常不再出现了,这说明添加了resultType属性之后,解决了之前的异常,可以看出resultType是不能省略的。

仔细观察控制台的日志信息,不难看出,结果查询出了一条。并且每个字段都查询到值了:Row: 1, 100, 宝马520Li, 41.00, 2022-09-01, 燃油车

但是奇怪的是返回的Car对象,只有id和brand两个属性有值,其它属性的值都是null,这是为什么呢?我们来观察一下查询结果列名和Car类的属性

名是否能一一对应:

查询结果集的列名:id, car_num, brand, guide_price, produce_time, car_type

Car类的属性名:id, carNum, brand, guidePrice, produceTime, carType

通过观察发现:只有id和brand是一致的,其他字段名和属性名对应不上,这是不是导致null的原因呢?我们尝试在sql语句中使用as关键字来给查

询结果列名起别名试试:

1

2

3

4

5

6

7

8

<select id="selectCarById" resultType="com.study.mybatis.pojo.Car">

  select

    id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType

  from

    t_car

  where

    id = #{id}

</select>

运行结果如下:

在这里插入图片描述

通过测试得知,如果当查询结果的字段名和java类的属性名对应不上的话,可以采用as关键字起别名,当然还有其它解决方案,我们后面再看。

查询多条数据

需求:查询所有的Car信息。

SQL语句如下:

1

2

3

4

5

6

7

8

<!--虽然结果是List集合,但是resultType属性需要指定的是List集合中元素的类型。-->

<select id="selectCarAll" resultType="com.study.mybatis.pojo.Car">

  <!--记得使用as起别名,让查询结果的字段名和java类的属性名对应上。-->

  select

    id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType

  from

    t_car

</select>

Java代码如下:

1

2

3

4

5

6

7

8

9

@Test

public void testSelectCarAll(){

    // 获取SqlSession对象

    SqlSession sqlSession = SqlSessionUtil.openSession();

    // 执行SQL语句

    List<Object> cars = sqlSession.selectList("selectCarAll");

    // 输出结果

    cars.forEach(car -> System.out.println(car));

}

运行结果如下:

5 关于SQL Mapper的namespace

在SQL Mapper配置文件中<mapper>标签的namespace属性可以翻译为命名空间,这个命名空间主要是为了防止sqlId冲突的。
创建CarMapper2.xml文件,代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

<?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="car2">

    <select id="selectCarAll" resultType="com.study.mybatis.pojo.Car">

        select

            id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType

        from

            t_car

    </select>

</mapper>

不难看出,CarMapper.xml和CarMapper2.xml文件中都有 id="selectCarAll"将CarMapper2.xml配置到mybatis-config.xml文件中。

1

2

3

4

<mappers>

  <mapper resource="CarMapper.xml"/>

  <mapper resource="CarMapper2.xml"/>

</mappers>

编写Java代码如下:

1

2

3

4

5

6

7

8

9

@Test

public void testNamespace(){

    // 获取SqlSession对象

    SqlSession sqlSession = SqlSessionUtil.openSession();

    // 执行SQL语句

    List<Object> cars = sqlSession.selectList("selectCarAll");

    // 输出结果

    cars.forEach(car -> System.out.println(car));

}

运行结果如下:

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.IllegalArgumentException: 
  selectCarAll is ambiguous in Mapped Statements collection (try using the full name including the namespace, or rename one of the entries) 
  【翻译】selectCarAll在Mapped Statements集合中不明确(请尝试使用包含名称空间的全名,或重命名其中一个条目)
  【大致意思是】selectCarAll重名了,你要么在selectCarAll前添加一个名称空间,要有你改个其它名字。

Java代码修改如下:

1

2

3

4

5

6

7

8

9

10

@Test

public void testNamespace(){

    // 获取SqlSession对象

    SqlSession sqlSession = SqlSessionUtil.openSession();

    // 执行SQL语句

    //List<Object> cars = sqlSession.selectList("car.selectCarAll");

    List<Object> cars = sqlSession.selectList("car2.selectCarAll");

    // 输出结果

    cars.forEach(car -> System.out.println(car));

}

运行结果如下:


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 :
相关文章
  • MyBatis中的N+1问题的解决方法
    N+1 问题是指在进行一对多查询时,应用程序首先执行一条查询语句获取结果集(即 +1),然后针对每一条结果,再执行 N 条额外的查询语句
  • MyBatis中 #{} 和 ${} 的区别介绍
    在MyBatis中,#{}和${}是两种常见的占位符,它们的作用和使用场景有所不同。理解它们的区别对于正确使用MyBatis非常重要。 在Mybatis面试中常
  • MyBatis实现CRUD的代码

    MyBatis实现CRUD的代码
    准备工作 创建module(Maven的普通Java模块):mybatis-002-crud pom.xml 打包方式jar 依赖: mybatis依赖 mysql驱动依赖 junit依赖 logback依赖 mybatis-config
  • MyBatis中if标签的基本使用

    MyBatis中if标签的基本使用
    在MyBatis框架中,if标签用于在构建SQL语句时,根据参数条件判断的结果,动态地选择加入或不加where条件中。 一 常见使用 在使用MyBatis处理
  • Java中的字节流和字符流介绍
    Java 中的输入输出(I/O)流主要分为字节流和字符流。这两类流为开发者提供了高效的文件读写方式,也解决了不同编码格式下的字符处理问
  • Java中缓冲流的使用与性能提升(让文件操作更高效
    在Java的I/O操作中,文件读写是常见且频繁的任务。特别是对于大文件或需要频繁访问文件的程序,如何提升I/O性能成为了一个重要的问题。
  • Java中如何自定义一个类加载器加载自己指定的类
    在 Java 中,类加载器(ClassLoader)负责把字节码文件(.class 文件)加载到 JVM 中,Java 的类加载机制给我们提供了高度的灵活性。通常情况下
  • Java实现Jar文件的遍历复制与文件追加

    Java实现Jar文件的遍历复制与文件追加
    一、引入依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 dependency groupIdcommons-io/groupId artifactIdcommons-io/artifactId version2.5/v
  • java中的Consumer、Supply如何实现多参数
    Java的Consumer接口只能接受一个参数,但可以通过自定义接口、使用Tuple或嵌套结构来实现对多个参数的处理,对于Supplier接口,它不能接受参数
  • 在Java中去除字符串末尾的换行符的常用方法
    在日常开发中,字符串操作是非常常见的需求,其中去除字符串末尾的换行符(\n)是一个很有代表性的场景。例如,从文件读取的文本、网
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计