动态SQL
基础SQL语句复习
整理后的基本SQL语句如下:
增加数据:
- 插入所有列的值:
INSERT INTO 表名 VALUES (值1, 值2, ...)
- 插入指定列的值:
INSERT INTO 表名 (列1, 列2, ...) VALUES (值1, 值2, ...)
删除数据:
- 删除满足条件的数据:
DELETE FROM 表名 WHERE 条件
修改数据:
- 更新数据:
UPDATE 表名 SET 列1=值1, 列2=值2 WHERE 条件
查询数据:
- 基本查询:
SELECT 列 FROM 表名 WHERE 条件
- 分组查询:
SELECT 列 FROM 表名 WHERE 条件 GROUP BY 列名 HAVING 条件
- 排序查询:
SELECT 列 FROM 表名 WHERE 条件 ORDER BY 列名 ASC/DESC
- 限制结果数量:
SELECT 列 FROM 表名 WHERE 条件 LIMIT 10, 5
以上是基本的SQL语句,用于增加、删除、修改和查询数据。SQL语句是用来操作关系型数据库的标准语言,通过这些简单的语句可以完成对数据库的各种操作。需要根据具体情况来灵活应用,并可以结合更复杂的查询条件和子查询来实现更复杂的数据操作和分析。
使用mybatis进行CRUD
前提准备
1.配置pom文件
2.指定MyBatis的Mapper XML文件所在的位置
在application.properties
中,我们可以使用mybatis.mapper-locations
属性来指定MyBatis的Mapper XML文件所在的位置。Mapper XML文件包含了SQL语句的定义,它们描述了数据库操作的具体逻辑。
具体配置如下:
mybatis.mapper-locations=classpath:mappers/*.xml
在上述配置中,mybatis.mapper-locations
属性的值是一个包含通配符*
的路径,表示Mapper XML文件所在的位置。在这个例子中,MyBatis会在classpath(类路径)下的mappers
目录查找所有以.xml
结尾的文件作为Mapper XML文件。这样配置后,MyBatis就能正确地找到并加载这些XML文件,并将其中的SQL语句注册到对应的Mapper接口中,供应用程序使用。
注意:classpath:
是一个特殊的前缀,用于表示在类路径下查找资源文件。因此,classpath:mappers/*.xml
表示在mappers
目录下查找所有以.xml
结尾的文件,该目录位于类路径下。如果你的Mapper XML文件在其他位置,需要根据实际情况进行相应的配置。
3.在启动类中添加注解
@MapperScan("com.example.mybatis2.mappers")
这行代码的作用是:
- 告知Spring Boot在
com.example.mybatis2.mappers
包及其子包下扫描所有的Mapper接口。 - 扫描到Mapper接口后,自动为其生成实现类,这些实现类中包含了MyBatis框架自动根据接口方法生成的SQL查询操作
- 注册这些Mapper接口和对应的实现类到Spring的应用上下文,使得其他组件可以方便地进行依赖注入并使用这些Mapper接口。
详细编写
xml:写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.example.mybatis_demo.mapper.UserMapper">
<!--编写查询sql语句-->
<!-- id对应的值为方法名,需要在namespace对应的接口(UserMapper接口)中添加方法-->
<!-- resultType是返回值,这里以User对象为存储容器 指定返回值为User-->
<select id="findUserById" resultType="com.example.mybatis_demo.pojo.User">
SELECT * FROM user;
</select>
<!--编写增加sql语句-->
<insert id="addUser">
insert into user values(null,'tom',12,1,'100086');
</insert>
<!--编写删除sql语句-->
<delete id="deleteById">
delete from user where id=6;
</delete>
<!--编写更新sql语句-->
<update id="updateUser">
update user set name='天龙' where id=3;
</update>
</mapper>
接口:写方法
package com.example.mybatis_demo.mapper;
import com.example.mybatis_demo.pojo.User;
import java.util.List;
public interface UserMapper {
// 这里写xmlSQL语句所使用的语句
List<User> findUserById();
void addUser();
void deleteById();
void updateUser();
}
test文件:写测试方法
package com.example.mybatis_demo;
import com.example.mybatis_demo.mapper.UserMapper;
import com.example.mybatis_demo.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
// 这里编写测试语句
//第一步 绑定启动类
@SpringBootTest(classes = MybatisDemoApplication.class)
//第二步使用@Autowired注入userMapper
class MybatisDemoApplicationTests {
@Autowired
UserMapper userMapper;
// @Test
// void contextLoads() {
// System.out.println(userMapper.findUserById(4));
// }
// 第三步添加测试
@Test
void contextLoads() {
List<User> user = userMapper.findUserById();
System.out.println(user);
}
@Test
void testAddUser(){
userMapper.addUser();
}
@Test
void testDeleteById(){
userMapper.deleteById();
}
@Test
void testUpdateUser(){
userMapper.updateUser();
}
}
优化CRUD操作参数处理
第一种:单个参数优化
1.1 设置参数为变量
在进行CRUD操作时,我们经常需要传递参数给MyBatis进行数据访问。为了优化参数传递的方式,我们可以将原来耦合的参数设置成#{参数名}
方式。这种方式不仅使代码更清晰,还能提高代码的可维护性和灵活性。
1.2 修改Mapper.xml文件
修改Mapper.xml中的SQL语句,使用#{参数名}
方式替代原来的硬编码参数。
<!--编写删除sql语句-->
<delete id="deleteById">
-- delete from user where id=6;
delete from user where id=#{id};
</delete>
1.3 Java文件更改
在Java的Mapper接口中,将原来的单个参数改为使用#{参数名}
的方式。
void deleteById(@Param("id") Integer id);
1.4 测试类更改
测试类中的调用也需进行相应修改。
@Test
void testDeleteById() {
userMapper.deleteById(2);
}
第二种:多个参数优化
2.1 设置多个参数为变量
在某些情况下,我们需要传递多个参数给MyBatis进行数据访问。同样,为了提高代码的可读性和维护性,我们可以使用#{参数名}
方式传递多个参数。
2.2 修改Mapper.xml文件
修改Mapper.xml中的SQL语句,使用#{参数名}
方式传递多个参数。
<update id="updateUser">
update user set name=#{name} where id=#{id};
</update>
2.3 Java文件更改
在Java的Mapper接口中,使用@Param
注解标明传入的参数名。
// *记住了!!! 如果我们传递的参数是多个需要告诉mybatis 哪个参数是谁@Param("username") String username*
//*@param username
// 主要是针对老版本,新版本不需要添加注解
void updateUser(@Param("name")String name,@Param("id") Integer id);
2.4 测试类更改
测试类中的调用方式保持不变。
@Test
void testUpdateUser() {
userMapper.updateUser("Jack", 1);
}
注意:在MyBatis中,#{}
是参数占位符,用于在SQL语句中替代具体的参数值。当我们在Mapper接口中定义了方法,并在XML文件中编写了SQL语句时,我们需要在SQL语句中指定参数的值,但由于参数值在运行时才能确定,所以我们使用#{}
来表示该位置应该被参数值替代。
具体来说,在你提供的SQL语句中,name=#{name}
中的两个name
分别表示:
#{name}
:这个name
是指Mapper接口中方法的参数名,例如在Java中的void updateUser(@Param("name") String name, @Param("id") Integer id);
方法中,name
是对应的参数名。name
:这个name
是指实体类(POJO)中的属性名,即User类中的name
属性。
MyBatis会根据这两个name
将实际的参数值与SQL语句进行绑定。在执行SQL语句时,会把#{name}
替换为User
对象中name
属性对应的值。因此,实际上执行的SQL语句可能是类似于update user set name='Jack' where id=2;
这样的形式,其中'Jack'
就是User
对象中name
属性的值,而2
则是updateUser
方法中的id
参数值。
这样的设计使得SQL语句与Java代码解耦,使得SQL语句更具可读性,并且在面对复杂的查询和动态SQL的情况下也能够方便地拼接参数值,提高了代码的灵活性和可维护性。
第三种:使用对象封装多个参数
3.1 设置参数为对象
为了进一步简化代码,我们可以将多个参数封装成一个对象,然后直接传递该对象给MyBatis进行数据访问。
3.2 修改Mapper.xml文件
修改Mapper.xml中的SQL语句,使用对象的属性作为参数。
<insert id="addUser">
insert into user values(null,#{name},#{age},#{gender},#{phone})
</insert>
3.3 Java文件更改
在Java的Mapper接口中,使用对象作为参数。
void addUser(User user);
3.4 测试类更改
测试类中的调用方式也相应进行修改。
@Test
void testAddUser() {
User user = new User();
user.setAge(11);
user.setName("Jack");
user.setPhone("100086");
user.setGender(1);
userMapper.addUser(user);
}
通过以上的参数优化处理,我们可以更好地组织代码,使得MyBatis的数据访问更加高效和优雅。同时,优化后的代码具备更好的可维护性和可读性,使开发过程更加流畅。让我们在MyBatis开发中,从参数优化处理中受益!
注解开发
MyBatis支持使用注解进行开发,这样可以避免编写繁琐的Mapper XML文件,更加简洁和直观地定义SQL语句。在使用注解进行开发时,我们可以在Mapper接口的方法上使用注解来编写SQL语句,从而实现数据的增删改查操作。以下是使用注解进行MyBatis开发的步骤和示例:
-
添加依赖: 首先,在
pom.xml
文件中添加MyBatis的依赖,以及数据库驱动的依赖(如MySQL驱动)。 -
创建实体类: 创建与数据库表对应的实体类(POJO),并在实体类中添加注解或XML映射文件来描述字段与表的映射关系。
-
创建Mapper接口: 创建Mapper接口,用于定义数据访问的接口。在方法上使用注解来编写SQL语句。
-
配置MyBatis: 在Spring Boot的配置类中,使用
@MapperScan
注解指定Mapper接口所在的包路径,使得MyBatis能够扫描并注册Mapper接口的实现。 -
编写业务逻辑: 在Service层编写业务逻辑,注入Mapper接口的实例,通过调用Mapper接口的方法来访问数据库。
以下是一个示例代码,演示如何使用注解进行MyBatis开发:
- 创建实体类
User.java
:
public class User {
private Integer id;
private String username;
private Integer age;
// 其他属性和对应的getter/setter方法
}
- 创建Mapper接口
UserMapper.java
:
import org.apache.ibatis.annotations.*;
@Mapper
public interface UserMapper {
@Insert("INSERT INTO user (username, age) VALUES (#{username}, #{age})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
void addUser(User user);
@Delete("DELETE FROM user WHERE id = #{id}")
void deleteUser(Integer id);
@Update("UPDATE user SET username = #{username}, age = #{age} WHERE id = #{id}")
void updateUser(User user);
@Select("SELECT * FROM user WHERE id = #{id}")
User getUserById(Integer id);
}
- 配置MyBatis:在Spring Boot的配置类中添加
@MapperScan
注解,指定Mapper接口的扫描路径。
import org.springframework.context.annotation.Configuration;
import org.mybatis.spring.annotation.MapperScan;
@Configuration
@MapperScan("com.example.mybatis2.mappers")
public class MyBatisConfig {
// MyBatis相关配置
}
- 编写业务逻辑
UserService.java
:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final UserMapper userMapper;
@Autowired
public UserService(UserMapper userMapper) {
this.userMapper = userMapper;
}
public void addUser(User user) {
userMapper.addUser(user);
}
public void deleteUser(Integer id) {
userMapper.deleteUser(id);
}
public void updateUser(User user) {
userMapper.updateUser(user);
}
public User getUserById(Integer id) {
return userMapper.getUserById(id);
}
}
通过上述步骤,我们就可以使用注解来定义SQL语句,实现对数据库的增删改查操作,而无需编写XML映射文件,使得代码更加简洁和直观。同时,MyBatis还提供了丰富的注解,可以满足各种复杂查询和数据库操作的需求。
插入数据返回主键
为什么需要设置插入数据后返回主键
- 获取插入数据的唯一标识: 数据库中的主键通常用于唯一标识一条记录。在插入数据后,我们通常希望获取刚插入数据的主键值,这样可以在后续的操作中方便地引用这条数据。
- 避免重复数据插入: 数据库表的主键通常是唯一的,插入数据时如果不返回主键,我们无法得知数据库中是否已经存在相同主键的记录,从而可能导致重复数据的插入。
- 数据关联和依赖: 在数据库中,表之间可能存在关联和依赖关系。比如,表A的主键被表B引用为外键,如果需要在表A插入一条记录,并将其主键作为外键插入到表B中,就需要先获取表A插入记录的主键值。
- 操作反馈和日志记录: 在实际应用中,我们通常需要记录插入数据的操作反馈或日志信息。通过返回主键值,我们可以方便地记录插入数据的成功或失败情况。
- 后续处理: 插入数据后,有时需要根据插入的数据进行一些后续处理。例如,插入一条订单记录后,需要在其他表中插入相关明细信息,此时就需要获取主键值。
如何使用
在MyBatis中,可以通过设置useGeneratedKeys
和keyProperty
属性来实现插入数据后返回主键的功能。这样做的好处是,在插入数据后,我们可以方便地获取生成的主键值,用于后续操作或记录。
第一种方式
-
在Mapper接口中的插入方法上添加
@Options
注解,并设置useGeneratedKeys
为true
,keyProperty
为要返回主键值的实体类属性。 -
在插入方法的SQL语句中使用数据库的主键生成机制来生成主键值。
创建Mapper接口
import org.apache.ibatis.annotations.*;
@Mapper
public interface UserMapper {
@Insert("INSERT INTO user (username, age) VALUES (#{username}, #{age})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
void addUser(User user);
// 其他方法...
}
-
在数据库中,确保
user
表的主键(假设为id
列)是自增的或由数据库自动生成的。 -
在Service层或Controller层调用插入方法并传入
User
对象:
@Service
public class UserService {
private final UserMapper userMapper;
@Autowired
public UserService(UserMapper userMapper) {
this.userMapper = userMapper;
}
public void addUser(User user) {
userMapper.addUser(user);
// 插入后,可以直接获取生成的主键值
Integer userId = user.getId();
System.out.println("插入成功,用户ID为:" + userId);
}
// 其他方法...
}
在上述示例中,当执行addUser
方法时,MyBatis会将插入后的主键值赋值给user
对象的id
属性,因为我们在@Options
注解中设置了keyProperty="id"
,表示要将生成的主键值设置到id
属性中。这样,我们就能够在插入数据后获取新插入数据的主键值。
第二种方式
是的,同样可以在Mapper XML文件中设置插入数据返回主键。在MyBatis的Mapper XML文件中,我们可以使用useGeneratedKeys
和keyProperty
属性来实现插入数据后返回主键的功能,与在注解中的设置类似。
以下是在Mapper XML文件中设置插入数据返回主键的示例:
- 创建Mapper XML文件
UserMapper.xml
:
<!-- UserMapper.xml -->
<mapper namespace="com.example.mybatis2.mappers.UserMapper">
<!-- 添加用户,并返回自动生成的主键 -->
<insert id="addUser" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (username, age) VALUES (#{username}, #{age})
</insert>
<!-- 其他SQL语句... -->
</mapper>
在上述示例中,我们在<insert>
元素上设置了useGeneratedKeys="true"
,表示使用数据库的主键生成机制来生成主键值。并且使用keyProperty="id"
,表示将生成的主键值设置到User
实体类的id
属性中。
- 创建Mapper接口
UserMapper
,并在其中声明方法对应上述XML中的ID:
@Mapper
public interface UserMapper {
void addUser(User user);
// 其他方法...
}
- 在Service层或Controller层调用插入方法并传入
User
对象:
@Service
public class UserService {
private final UserMapper userMapper;
@Autowired
public UserService(UserMapper userMapper) {
this.userMapper = userMapper;
}
public void addUser(User user) {
userMapper.addUser(user);
// 插入后,可以直接获取生成的主键值
Integer userId = user.getId();
System.out.println("插入成功,用户ID为:" + userId);
}
// 其他方法...
}
在上述示例中,当执行addUser
方法时,MyBatis会将插入后的主键值赋值给User
对象的id
属性,因为我们在XML文件中设置了keyProperty="id"
。这样,我们就能够在插入数据后获取新插入数据的主键值。
列成员变量不一致问题(手动映射与驼峰映射)
手动映射结果和使用mybatis.configuration.map-underscore-to-camel-case=true
是两种解决列成员变量不一致问题的方法,它们可以用于处理数据库表列名和Java对象成员变量名之间的命名规则不一致问题。
- 手动映射结果: 在MyBatis中,我们可以手动定义结果集映射关系,即将数据库表列名映射到Java对象成员变量名。这可以通过在Mapper接口的SQL语句中使用别名或在Mapper XML文件中使用
<resultMap>
来实现。
例如,假设数据库表中的列名为user_id
,而Java对象的成员变量名为userId
,我们可以在SQL语句中使用别名来映射:
@Select("SELECT user_id AS userId, username, age FROM user WHERE user_id = #{userId}")
User getUserById(Integer userId);
或者在Mapper XML文件中定义<resultMap>
来手动映射结果集:
<mapper namespace="com.example.mybatis2.mappers.UserMapper">
<resultMap id="userResultMap" type="User">
<id property="userId" column="user_id" />
<result property="username" column="username" />
<result property="age" column="age" />
</resultMap>
<select id="getUserById" resultMap="userResultMap">
SELECT user_id, username, age FROM user WHERE user_id = #{userId}
</select>
</mapper>
- 使用驼峰映射
mybatis.configuration.map-underscore-to-camel-case=true
: MyBatis提供了一个全局配置选项map-underscore-to-camel-case
,用于自动将数据库表的下划线命名转换为Java对象的驼峰命名。
设置mybatis.configuration.map-underscore-to-camel-case=true
后,MyBatis会在查询结果映射时,自动将数据库表列名的下划线转换为Java对象成员变量的驼峰命名。例如,数据库表的列名为user_id
,则对应Java对象的成员变量名为userId
。
# application.properties
mybatis.configuration.map-underscore-to-camel-case=true
使用该配置后,我们可以简化Mapper接口方法和SQL语句的编写,不再需要手动映射结果。
@Mapper
public interface UserMapper {
User getUserById(Integer userId);
}
<!-- UserMapper.xml -->
<mapper namespace="com.example.mybatis2.mappers.UserMapper">
<select id="getUserById">
SELECT user_id, username, age FROM user WHERE user_id = #{userId}
</select>
</mapper>
总的来说,手动映射结果和使用mybatis.configuration.map-underscore-to-camel-case=true
都是解决列成员变量不一致问题的有效方法。手动映射结果适用于需要更精细的映射控制或特殊映射情况,而使用全局配置则可以简化映射过程,使代码更加简洁和易读。根据具体情况,可以选择适合自己项目的方法。