仍然以前面的User表为模型,实行增删改查操作
一、增
UserDao:
void create(User user);
mapper:
<insert id="create" parameterType="com.example.test.model.User">
INSERT INTO user (
username, password, nickname, phone, status, create_time, icon, gender, birthday
)
VALUES
(
#{username}, #{password}, #{nickname}, #{phone}, #{status}, now(), #{icon}, #{gender}, #{birthday}
);
</insert>
增加数据使用 insert
标签
insert
的几个属性说明:
id
唯一标识,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致parameterType
参数的类型,使用动态代理之后和方法的参数类型一致useGeneratedKeys
开启主键回写keyColumn
指定数据库的主键keyProperty
主键对应的pojo属性名标签内部
具体的sql语句
UserServiceImpl:
@Override
public void create(User user) {
userDao.create(user);
}
UserController:
@PostMapping("/create")
public void create(User user) {
userService.create(user);
}
请求测试:
@Insert
如果使用注解,可以使用 @Insert
插入数据:
@Insert("INSERT INTO user(user_name,pass_word,user_sex) VALUES(#{userName}, #{passWord}, #{userSex})")
void create(User user);
二、删
UserDao:
void delete(Long id);
mapper:
<delete id="delete">
DELETE FROM user where id=#{id}
</delete>
删除数据使用 delete
标签
delete
的几个属性说明:
id
唯一标识,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致parameterType
参数的类型,使用动态代理之后和方法的参数类型一致标签内部
具体的sql语句。
UserServiceImpl:
@Override
public void delete(Long id) {
userDao.delete(id);
}
UserController:
@PostMapping("/delete/{id}")
public void delete(@PathVariable Long id) {
userService.delete(id);
}
请求测试:http://localhost:10010/user/delete/21
@Delete
如果使用注解,可以使用 @Delete
删除数据:
@Delete("DELETE FROM user WHERE id=#{id}")
void delete(Long id);
三、改
UserDao:
void update(User user);
mapper:
<update id="update">
UPDATE user
<trim prefix="set" suffixOverrides=",">
<if test="username!=null">username = #{username},</if>
<if test="password!=null">password = #{password},</if>
<if test="nickname!=null">nickname = #{nickname},</if>
<if test="gender!=null">gender = #{gender},</if>
create_time = now(),
</trim>
WHERE
(id = #{id});
</update>
修改数据使用 update
标签,由于传入的字段数据是可选的,使用 trim
包裹,使用 if
判断后生成对应的sql
update
的几个属性说明:
id
唯一标识,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致parameterType
参数的类型,使用动态代理之后和方法的参数类型一致标签内部
具体的sql语句
UserServiceImpl:
@Override
public void update(User user) {
userDao.update(user);
}
UserController:
@PostMapping("/update")
public void update(User user) {
userService.update(user);
}
请求测试:http://localhost:8080/user/update?id=19&username=test&password=abc&nickname=t&gender=2
@Update
如果使用注解,可以使用 @Update
修改数据:
@Update("UPDATE user SET user_name=#{userName},nick_name=#{nickName} WHERE id=#{id}")
void update(User user);
四、查
查询单条数据
UserDao:
User query(Long id);
mapper:
<select id="query" resultType="com.example.test.model.User">
SELECT * from user where id=#{id}
</select>
查询数据使用 select
标签,使用 resultType
指定返回数据类型
UserServiceImpl:
@Override
public User query(Long id) {
return userDao.query(id);
}
UserController:
@GetMapping("/{id}")
public User query(@PathVariable Long id) {
return userService.query(id);
}
请求测试:http://localhost:10010/user/19
查询多条数据
UserDao:
List<User> list();
mapper:
<select id="list" resultType="com.example.test.model.User">
SELECT * from user
</select>
查询数据使用 select
标签,使用 resultType
指定返回数据类型
UserServiceImpl:
@Override
public List<User> list() {
return userDao.list();
}
UserController:
@GetMapping("/list")
public List<User> list() {
return userService.list();
}
请求测试:http://localhost:10010/user/list
@Select
可以使用 @Select
注解查询数据。示例:
public interface UserMapper {
@Select("SELECT * FROM user")
@Results({
@Result(property = "userSex", column = "user_sex", javaType = UserSexEnum.class),
@Result(property = "nickName", column = "nick_name")
})
List<UserEntity> getAll();
@Select("SELECT * FROM user WHERE id = #{id}")
@Results({
@Result(property = "userSex", column = "user_sex", javaType = UserSexEnum.class),
@Result(property = "nickName", column = "nick_name")
})
UserEntity getOne(Long id);
@Select("SELECT count(*) FROM user")
int count();
}
五、#
和$
的区别
#{}
预编译的方式preparedstatement,使用占位符替换,防止sql注入,一个参数的时候,任意参数名可以接收${}
普通的Statement,字符串直接拼接,不可以防止sql注入,一个参数的时候,必须使用${value}
接收参数
示例:
DAO中:
User queryUserListByName2(@Param("username") String username2);
Mapper中:
<select id="queryUserListByName1" resultType="com.example.test.model.User">
select * from tb_user WHERE user_name=#{username}
</select>
<select id="queryUserListByName2" resultType="com.example.test.model.User">
select * from tb_user WHERE user_name='${username}'
</select>
注意到,使用$
时需要手动添加''
六、参数传递
实体参数
如果传入的是一个实体,mapper将自动解开其内部参数的名称:
void insert(UserEntity user);
在mapper中解开:
<insert id="insert" parameterType="UserEntity">
INSERT INTO
user
(user_name, pass_word, user_sex)
VALUES
(#{userName}, #{passWord}, #{userSex})
</insert>
非实体单参数
如果非实体,且只有一个参数,DAO中的参数会自动对应到mapper:
public List<User> queryUserByTableName(String tableName);
<select id="queryUserByTableName" resultType="com.example.test.model.User">
select * from ${tableName}
</select>
非实体多参数
但是如果有多个参数,且在DAO中没有指定参数的名字:
public User login(String userName, String password);
<select id="login" resultType="com.example.test.model.User">
select * from tb_user where user_name = #{userName} and password = #{password}
</select>
这样就会报错:
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.apache.ibatis.binding.BindingException: Parameter 'userName' not found. Available parameters are [0, 1, param1, param2]
### Cause: org.apache.ibatis.binding.BindingException: Parameter 'userName' not found. Available parameters are [0, 1, param1, param2]
解决方案一:使用位置参数
<select id="login" resultType="com.example.test.model.User">
select * from tb_user where user_name = #{0} and password = #{1}
</select>
解决方案二:使用param参数
<select id="login" resultType="com.example.test.model.User">
select * from tb_user where user_name = #{param1} and password = #{param2}
</select>
终极解决方案:在DAO中使用 @Param
注解
public User login(@Param("userName") String userName, @Param("password") String password);
<select id="login" resultType="com.example.test.model.User">
select * from tb_user where user_name = #{userName} and password = #{password}
</select>
七、枚举类型
如果实体中某个字段为枚举类型,比如性别:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserEntity implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String userName;
private String passWord;
private UserSexEnum userSex;
private String nickName;
public UserEntity(String userName, String passWord, UserSexEnum userSex) {
super();
this.passWord = passWord;
this.userName = userName;
this.userSex = userSex;
}
}
性别的枚举如下:
public enum UserSexEnum {
MAN, WOMAN
}
那么数据表中的字段应为超过枚举项字段最大长度的一个字符串:
CREATE TABLE if not exists `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_name` varchar(255) DEFAULT NULL,
`pass_word` varchar(255) DEFAULT NULL,
`user_sex` varchar(10) DEFAULT NULL,
`nick_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
插入数据:
userMapper.insert(new UserEntity("xiaoyu", "a123456", UserSexEnum.MAN));
userMapper.insert(new UserEntity("qiaoer", "b123456", UserSexEnum.WOMAN));
插入后:
八、设置日期时间格式
在模型中配置 @JsonFormat
或者 @DateTimeFormat
注解,指定日期时间格式:
...
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
@Data
public class User implements Serializable {
...
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
}
这样,在查询或添加数据的时候,都可以使用指定的格式了。
时间格式的返回示例:
{
"createTime": "2021-01-06 14:45:43",
"updateTime": "2021-01-06T14:46:20.000+0000"
}