mybatis动态生成sql语句的实现示例

 更新时间:2024年11月05日 10:15:14   作者:代码代码快快显灵  
在MyBatis中,动态SQL是一个非常重要的特性,它允许我们根据条件动态地生成SQL语句,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

在 Java 编程中,我们常常需要将数据传递给 SQL 查询,特别是在动态生成 SQL 语句时,通常会用到 Map 这种集合类。Map 可以将多个键值对传递给 SQL 语句的占位符,完成动态参数绑定的功能。我们下面详细讲解图中的知识点。

1. Map 的基本用法

Map 是 Java 集合框架中的一种数据结构,它以键值对 (key-value) 的形式存储数据。Map 中的键唯一且不能重复,而值可以重复。常用的实现类包括 HashMapTreeMap 等。

示例代码

Map<String, Object> map = new HashMap<>();
map.put("k1", "1111");
map.put("k2", "比亚迪汉");
map.put("k3", 10.0);
map.put("k4", "2020-11-11");
map.put("k5", "电车");

这里我们创建了一个 HashMap,并通过 put 方法将一些数据存入 Map。键是 String 类型,值是 Object 类型,意味着可以存放不同类型的数据(如字符串、数字、日期等)。

2. 占位符 #{} 的使用

在执行 SQL 语句时,为了防止 SQL 注入和简化代码,我们经常使用占位符将 SQL 参数动态地传入。( ? 是 JDBC 中的占位符,用于预编译 SQL 语句中的参数。在使用 JDBC 时,SQL 语句通常是预编译的,? 用于表示一个位置,在执行时由具体的参数替换。占位符 #{} 这一语法主要用于一些持久化框架,如 MyBatis。

SQL 语句示例

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

在这个 SQL 语句中,#{k1}#{k2} 等占位符将会在运行时被替换为 Map 中对应的值。框架会根据占位符的键来查找 Map 中的值并动态替换。如果键不存在,则返回 null这个语句通常配置在通常用于 MyBatis 的 SQL 映射的XML文件中

注意

  • 如果 Map 中没有提供某个占位符对应的值,查询执行时可能会插入 null,这可能导致意外的行为。
  • 使用占位符 #{} 可以防止 SQL 注入,因为框架在执行时会自动进行预处理。

3. Map 键名与数据库字段名的对应关系

为了使代码更加易读、维护更加方便,我们通常建议将 Map 中的键名与数据库字段名保持一致。这样一来,不仅能够直观地映射参数,还能避免因键名不统一而导致的问题。

map.put("carNum", "1111");
map.put("brand", "比亚迪汉2");
map.put("guidePrice", 10.0);
map.put("produceTime", "2020-11-11");
map.put("carType", "电车");

在这个例子中,我们将 Map 的键名改为 carNumbrand 等,和数据库表的列名一致。这样一来,代码就更容易理解和维护。

SQL 语句

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

POJO 类实现动态传参

1. POJO 类与 SQL 占位符传递

POJO(Plain Old Java Object) 是指普通的 Java 对象,通常用作数据传输对象。在 Java 应用中,我们可以通过 POJO 类的属性来传递 SQL 语句中的参数。

Car car = new Car(null, "3333", "比亚迪秦", 30.0, "2020-11-11", "新能源");

在这个例子中,Car 是一个 POJO 类,包含一些车辆信息的属性。通过实例化这个类,我们可以将具体的值传入到 SQL 语句中的占位符。

2. 占位符 #{} 的使用

在 MyBatis 等持久化框架中,使用占位符 #{} 来表示将 POJO 的属性值注入到 SQL 语句中。大括号 {} 里面填写的内容是 POJO 类的属性名(严格意义上来说:如果使用P0J0对象传递值的话,这个{}里面写的是get方法的方法名去掉get,然后将剩下的单词首字母小写,然后放进去。

SQL 语句示例

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

3. 占位符与属性对应的规则

MyBatis 会自动根据 POJO 类中的属性名来查找对应的 getter 方法。如果 POJO 类中没有提供对应的 getter 方法,则会报错。

错误示例

There is no getter for property named 'xyz' in 'class com.powernode.mybatis.pojo.Car'

这是因为 MyBatis 尝试通过 getXyz() 方法来获取 xyz 属性的值,但 POJO 类中没有定义这个方法。为了避免这种错误,我们需要在 POJO 类中提供每个属性的 getter 和 setter 方法。

4. 如何解决没有 getter 方法的问题?

如果遇到没有对应 getter 方法的情况,可以通过在 POJO 类中手动添加相应的 getter 方法来解决。比如:

public String getXyz() {
    return xyz;
}

5. 占位符 #{} 的使用规则

通过这个错误示例,我们可以总结出占位符的使用规则:MyBatis 是通过反射机制来调用 getter 方法。也就是说,在 #{} 占位符中写的内容(如 #{carNum})并不直接对应 POJO 的属性名,而是对应属性的 getter 方法。

规则

  • 占位符 #{} 中的内容是首字母小写形式。
  • 占位符内部自动调用属性的 getter 方法,因此命名应符合 Java 的命名规范。例如:
    • getUsername() 对应的占位符为 #{username}
    • getEmail() 对应的占位符为 #{email}

占位符 #{} 中的内容确实是与 POJO 类的属性相关,但 MyBatis 实际上是通过 调用 POJO 类的 getter 方法 来获取这些值的,而不是直接访问属性本身。因此,为了确保 MyBatis 能正确地映射 SQL 参数,POJO 类中的 getter 方法必须与占位符中的名字相匹配。 

删除DELETE操作:

 1. 删除操作的实现

int count = sqlSession.delete("deleteById", 59);

这行代码展示了通过 sqlSession.delete() 方法来执行删除操作,其中:

  • sqlSession:MyBatis中的会话对象,允许我们与数据库进行交互。
  • "deleteById":这是Mapper XML文件中定义的SQL语句的唯一标识符,用来指定删除操作。
  • 59:这是要传递给SQL语句的参数,即要删除的记录的ID

2. MyBatis Mapper 文件中的SQL语句 

<delete id="deleteById">
    delete from t_car where id = #{fdsfd}
</delete>

这是在MyBatis的Mapper XML文件中定义的删除操作,具体解释如下:

  • <delete id="deleteById">:这是定义一个删除操作的方法,id 是这个方法的唯一标识符,名称为 deleteById,与Java代码中调用的 deleteById 相对应。
  • delete from t_car where id = #{fdsfd}:这是一个标准的SQL删除语句,意思是从表 t_car 中删除 id 为 #{fdsfd} 的记录。
    • #{fdsfd}:这是MyBatis的参数占位符,表示将传递的参数(在Java代码中传递的 59)注入到这个位置。fdsfd 是参数名,可以根据需要定义。

3. 占位符的说明

注意:如果占位符只有一个,那么 #{} 的大括号里可以随意。但是最好见名知意。

这里说明了 #{} 是MyBatis的占位符,用于绑定参数。虽然在某些情况下可以随意使用参数名(如 fdsfd),但是为了代码的可读性和维护性,建议使用有意义的名称,比如 id

例如,改为:

<delete id="deleteById">
    delete from t_car where id = #{id}
</delete>

这样更直观,容易理解。

4. 整体流程总结

  • 在Java代码中,我们通过 sqlSession.delete("deleteById", 59) 来调用Mapper文件中定义的 deleteById 删除方法,并传递 id = 59
  • MyBatis会将 59 替换到 delete from t_car where id = #{id} 的SQL语句中,生成最终的SQL语句 delete from t_car where id = 59 并执行,最终删除 t_car 表中 id 为 59 的记录。

更新操作:

1. 更新操作的SQL语句

<update id="updateById">
    update t_car set
        car_num=#{carNum},
        brand=#{brand},
        guide_price=#{guidePrice},
        produce_time=#{produceTime},
        car_type=#{carType}
    where
        id = #{id}
</update>

这是在MyBatis的Mapper XML文件中定义的更新操作。解释如下:

  • <update id="updateById">:定义一个更新操作,id 是唯一标识符,这里使用 updateById,与Java代码中的方法名一致。
  • update t_car set ... where id = #{id}:这是SQL的更新语句,意图是将 t_car 表中的某条记录进行更新,具体是通过 id 来定位记录,然后对表中的多个字段进行更新。

这里使用 #{} 作为MyBatis的占位符,类似于之前的删除操作。它会在执行时将参数替换为实际值。具体字段说明:

  • #{carNum}:汽车编号
  • #{brand}:品牌
  • #{guidePrice}:指导价格
  • #{produceTime}:生产日期
  • #{carType}:汽车类型
  • #{id}:记录的唯一标识符,即要更新的汽车记录的 id

2. Java代码中的更新操作

Car car = new Car(4L, "9999", "凯美瑞", 30.3, "1999-11-10", "燃油车");
int count = sqlSession.update("updateById", car);

这里通过 new Car() 创建了一辆 Car 对象,包含了所有要更新的属性。各个属性与Mapper XML中的占位符对应。

  • 4L:表示汽车的 id,也就是SQL语句中 id 字段要更新的记录。null 不能赋值给基本类型 long,但可以赋值给 Long 这样的包装类,所以使用)
  • "9999":对应 carNum,汽车编号。
  • "凯美瑞":对应 brand,汽车品牌。
  • 30.3:对应 guidePrice,指导价格。
  • "1999-11-10":对应 produceTime,生产日期。
  • "燃油车":对应 carType,汽车类型。

然后调用 sqlSession.update("updateById", car); 进行更新操作。MyBatis会将 car 对象的属性传递给对应的SQL语句中的占位符,生成最终的SQL语句并执行更新。

3. 详细流程说明

MyBatis会根据Java代码中的 car 对象的属性,替换Mapper XML中的占位符,生成最终的SQL语句。

假设 car 对象的 id 是4,那么生成的SQL语句大致如下

update t_car set
    car_num='9999',
    brand='凯美瑞',
    guide_price=30.3,
    produce_time='1999-11-10',
    car_type='燃油车'
where
    id = 4;

执行这条SQL语句后,t_car 表中 id 为4的记录就会被更新成新值。

更新后,sqlSession.update() 方法会返回受影响的行数,即 count

select查找操作 

1. MyBatis 中的 select 标签

作用:MyBatis 使用 select 标签来编写 SQL 查询语句,定义如何从数据库中获取数据。在这个例子中,它用于根据 id 字段查询 t_car 表中的记录。

SQL 语句解释

<select id="selectById" resultType="com.powernode.mybatis.pojo.Car">
    select * from t_car where id = #{id}
</select>

id 属性id="selectById" 是一个唯一标识符,表示这条 SQL 语句在 MyBatis 配置中的 ID。当你在代码中调用 sqlSession.selectOne("selectById", 参数) 时,MyBatis 会根据这个 ID 找到对应的 SQL 语句。

SQL 查询select * from t_car where id = #{id} 是实际的 SQL 语句。#{id} 是 MyBatis 的动态 SQL 占位符,它会在运行时将你传入的参数(比如 1)替换为实际的查询条件。

  • #{} 是 MyBatis 语法,用于从传递的参数中获取值,防止 SQL 注入。
  • select * 是查询所有列,你可以根据需要替换为具体的列名(例如:select id, name, brand)。

2. resultType 属性

作用resultType 属性告诉 MyBatis 查询结果应该映射成什么样的 Java 对象。也就是说,当从数据库中获取到数据后,MyBatis 会根据 resultType 中指定的类型来创建该类型的对象,并将查询结果封装到这个对象中。

在此例子中的使用

resultType="com.powernode.mybatis.pojo.Car"

这里 resultType="com.powernode.mybatis.pojo.Car" 指定了 Car 类为查询结果的映射对象类型。即查询到的 t_car 表中的记录会被封装成 Car 类的实例。

全限定类名:com.powernode.mybatis.pojo.Car 是 Car 类的全限定类名,即包括了包名和类名。这是 MyBatis 推荐的写法,因为这样可以确保避免类名冲突,并确保 MyBatis 能找到正确的类。

resultType 的作用机制

查询结果(即数据库中的一条记录)会被转换为 Java 对象。MyBatis 会根据数据库表中的列名与 Car 类的属性名进行匹配,如果列名与属性名相同,MyBatis 就会自动将查询结果中的列值赋给对应的属性。

例如:假设 t_car 表有以下列:

  • idnamebrand
  • 对应 Car 类的属性为:idnamebrand,MyBatis 会自动将数据库中的 id 列的值赋给 Car 类中的 id 属性,依此类推。

注意事项

如果数据库中的列名和 Java 类中的属性名不一致,你需要使用别名(AS)或者 resultMap 进行手动映射。

1. 假设的数据库表 t_car

CREATE TABLE t_car (
    car_id INT PRIMARY KEY,
    car_name VARCHAR(50),
    car_brand VARCHAR(50)
);

在这个表中,列名是 car_idcar_name, 和 car_brand

Java 类 Car

public class Car {
    private int id;
    private String name;
    private String brand;

    // Getters and setters
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }
}

在 Java 类 Car 中,属性名分别是 idname, 和 brand,显然与数据库表 t_car 的列名不一致。

解决办法:使用 resultMap 进行手动映射

由于列名和属性名不一致,直接使用 resultType 是无法自动映射的,这时我们可以使用 resultMap 进行手动映射。

3. MyBatis 映射配置:起别名

<select id="selectById" resultType="com.powernode.mybatis.pojo.Car">
    select car_id as id, car_name as name, car_brand as brand
    from t_car
    where car_id = #{id}
</select>

在这个配置中:

  • car_id as id:把 car_id 列的查询结果映射为 id,从而与 Java 类 Car 的 id 属性对应。
  • car_name as name:把 car_name 列的查询结果映射为 name,与 Car 类中的 name 属性对应。
  • car_brand as brand:把 car_brand 列的查询结果映射为 brand,与 Car 类中的 brand 属性对应。

SQL 查询select * from t_car where car_id = #{id},通过 #{id} 来传递 Java 方法中的参数。

这样,通过使用 AS 设置别名,可以直接在 SQL 语句中将数据库的列名与 Java 类的属性名进行对应,而无需修改数据库或 Java 类。

3. selectOne 方法

作用selectOne 是 MyBatis 提供的一个方法,用于执行返回单条记录的查询。当我们确定查询的结果是唯一的(例如,查询主键),可以使用这个方法。如果查询结果返回多条记录,MyBatis 会抛出异常(TooManyResultsException)。

用法解释

Car car = sqlSession.selectOne("selectById", 1);

sqlSession 是 MyBatis 中操作数据库的会话对象,类似于 JDBC 中的 Connection 对象。

selectOne("selectById", 1):调用了 selectById 这个 SQL 查询,并传递了参数 1。这个 1 会替换 SQL 中的 #{id} 占位符,最终执行的 SQL 会是:

select * from t_car where id = 1;

返回的结果会是一个 Car 对象,存储在变量 car 中。

 select查所有的数据

sql语句

<select id="selectAll" resultType="com.powernode.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>

在这个查询中,使用了别名将数据库表中的列名映射到 Java 类 Car 中的属性名:

  • car_num as carNum:将数据库中的 car_num 列映射到 Car 类中的 carNum 属性。
  • guide_price as guidePrice:将数据库中的 guide_price 列映射到 Car 类中的 guidePrice 属性。
  • produce_time as produceTime:将数据库中的 produce_time 列映射到 Car 类中的 produceTime 属性。
  • car_type as carType:将数据库中的 car_type 列映射到 Car 类中的 carType 属性。

Java 代码中的 selectList 调用 

List<Car> cars = sqlSession.selectList("selectAll");
  • selectList 方法:MyBatis 中的 selectList 方法用于返回一个 List 集合,集合中的每个元素是从数据库查询到的每一条记录的 Java 对象。在这个例子中,查询结果将会封装为一个 Car 对象的列表。

  • resultType 属性:在 SQL 配置中,resultType 依然用于指定封装查询结果的 Java 类类型,这里是 com.powernode.mybatis.pojo.Car,表示查询结果会封装成 Car 类的对象。

注意事项

  • resultType 指定的类型:需要注意的是,resultType 并不是指定集合的类型,而是指定集合中的每个元素类型。在这个例子resultType="com.powernode.mybatis.pojo.Car",意味着 MyBatis 会将查询结果的每一条记录封装为 Car 对象。

  • selectList 返回的结果:调用 selectList("selectAll") 会返回一个 List 集合,集合中的每个元素对应于查询结果中的一条记录,并会封装为指定的 Car 对象。

到此这篇关于mybatis动态生成sql语句的实现示例的文章就介绍到这了,更多相关mybatis动态生成sql语句内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringMVC 异常处理机制与自定义异常处理方式

    SpringMVC 异常处理机制与自定义异常处理方式

    这篇文章主要介绍了SpringMVC 异常处理机制与自定义异常处理方式,具有很好的开车价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • java处理解析带有反斜杠的json

    java处理解析带有反斜杠的json

    在Java中操作JSON数据是一项常见的任务,其中一个常见的问题是如何在JSON字符串中包含反斜杠,本文主要介绍了java处理解析带有反斜杠的json,感兴趣的可以了解一下
    2024-01-01
  • Spring-Data-JPA整合MySQL和配置的方法

    Spring-Data-JPA整合MySQL和配置的方法

    这篇文章主要介绍了Spring Data JPA整合MySQL和配置,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • map实现按value升序排序

    map实现按value升序排序

    map内部是按照hash算法存储的,但如果能对map排序在某些时候还是有用的,下面实现对map按照value升序排序,实现对map按照key排序,大家参考使用吧
    2014-01-01
  • spring boot设置过滤器、监听器及拦截器的方法

    spring boot设置过滤器、监听器及拦截器的方法

    这篇文章主要给大家介绍了关于spring boot设置过滤器、监听器及拦截器的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用spring boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-04-04
  • Intellij IDEA如何去掉@Autowired 注入警告的方法

    Intellij IDEA如何去掉@Autowired 注入警告的方法

    这篇文章主要介绍了Intellij IDEA如何去掉@Autowired 注入警告的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • 解决@RequestMapping和@FeignClient放在同一个接口上遇到的坑

    解决@RequestMapping和@FeignClient放在同一个接口上遇到的坑

    这篇文章主要介绍了解决@RequestMapping和@FeignClient放在同一个接口上遇到的坑,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • Java中策略设计模式的实现及应用场景

    Java中策略设计模式的实现及应用场景

    策略设计模式是Java中一种常用的设计模式,它通过定义一系列算法并将其封装成独立的策略类,从而使得算法可以在不影响客户端的情况下随时切换。策略设计模式主要应用于系统中存在多种相似的算法、需要灵活调整算法逻辑或者需要扩展新的算法等场景
    2023-04-04
  • 使用Java实现转换扫描的文档为可搜索的PDF

    使用Java实现转换扫描的文档为可搜索的PDF

    这篇文章主要为大家详细介绍了如何使用Java实现转换扫描的文档为可搜索的PDF,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-12-12
  • 详解Java多线程编程中互斥锁ReentrantLock类的用法

    详解Java多线程编程中互斥锁ReentrantLock类的用法

    Java多线程并发的程序中使用互斥锁有synchronized和ReentrantLock两种方式,这里我们来详解Java多线程编程中互斥锁ReentrantLock类的用法:
    2016-07-07

最新评论