上篇博客我们围绕Mybatis链接数据库进行了相关概述,并对Mybatis的配置文件进行详细的描述,本篇博客也是建立在上篇博客之上进行的,在上面博客搭建的框架基础上,我们对MyBatis实现简单的增删改查操作进行重点概述,在MyBatis中实现简单的增删改查,算是我们在处理业务的时候经常干的事情,使用Mybatis可以帮助我们将数据库操作封装在映射文件或者映射接口中,让开发人员可以通过简单的配置或者接口方法来执行数据库操作,进而无需重复编写繁琐的SQL,并且可以灵活编写SQL语句,可以根据实际需求进行SQL拼接,从而提高数据库操作的灵活性和可用性。
项目目录结构
PS: 上述的Service层是我为了按照规范进行开发创建的相关类,实际开发中则需要按照上述规范进行,而本篇博客我们将不会使用到service层,所以,读者可以无需创建Service和ServiceImpl。
关注点:
- MyBatis实现简单的增删改查也会实现MyBatis实现一些相对复杂的查询功能,其中包括查询List集合,查询一个实体类对象,以及查询单个数据,查询单条为Map的集合和多条Map的集合。
- MyBatis获取参数值的两种方式:
${}和#{}
- 特殊SQL的执行:模糊查询,批量删除,动态设置表名,添加功能获取自增的主键
- 自定义映射resultMap,多对一和一对多映射关系处理
数据库
sql
CREATE TABLE `test`.`user` (
`id` int(11) NOT NULL,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`sex` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
CREATE TABLE `test`.`book` (
`uid` int(11) NOT NULL COMMENT '用户id',
`book` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '用户借的书的名称',
`cool` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT 'cool星级',
PRIMARY KEY (`uid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
实体Bean
java
public class Book {
private Integer uid;
private String book;
private String cool;
public Book() {
}
public Book(Integer uid, String book, String cool) {
this.uid = uid;
this.book = book;
this.cool = cool;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getBook() {
return book;
}
public void setBook(String book) {
this.book = book;
}
public String getCool() {
return cool;
}
public void setCool(String cool) {
this.cool = cool;
}
@Override
public String toString() {
return "Book{" +
", uid=" + uid +
", book='" + book + '\'' +
", cool='" + cool + '\'' +
'}';
}
}
java
public class User {
private int id;
private String name;
private String username;
private String sex;
private Book book;
private Integer uid;
private String bookName;
private String cool;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", username='" + username + '\'' +
", sex='" + sex + '\'' +
", book=" + book +
'}';
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getCool() {
return cool;
}
public void setCool(String cool) {
this.cool = cool;
}
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
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 getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public User(int id, String name, String username, String sex) {
this.id = id;
this.name = name;
this.username = username;
this.sex = sex;
}
public User() {
}
}
Mapper映射层接口
java
@Mapper
public interface UserMapper {
/**
* 查询用户对象
*/
User selectUser(@Param("user") User user);
/**
* 插入用户数据
*/
int insertUser(User user);
/**
* 更新数据
*/
int updateUser(@Param("user") User user);
/**
* 删除用户数据
*/
int deleteUser(int id);
/**
* 批量删除用户数据
*/
int deleteUserBatch(@Param("ids") String ids);
/**
* 查询所有用户数据
*/
List<User> selectAll();
/**
* 查询单条数据,并转化为Map对象数据
*/
Map<String,Object> getUserToMap(@Param("id") int id);
/**
* 查询多条数据斌并转化为Map对象数据
*/
List<Map<String,Object>> get100UserToMap();
/**
* 查询多条数据并转换为Map对象的数据的第二种方式
*/
@MapKey("id")
Map<Integer,User> get100UserToMap2();
/**
* 模糊查询
*/
List<User> selectUserLike(@Param("user") User user);
/**
* 动态设置表名查询数据
*/
List<User> selectUserByTableName(@Param("tableName") String tableName);
/** 根据用户id查询信息*/
User getUserById(int id);
/** 管理其他表一对一查询 */
User getUserBookById(int id);
}
Mapper接口对应的映射xml文件
关注
Mapper文件我们需要注意的是:
resultType
:resultType
用于指定查询结果的类型。它可以是Java的基本数据类型(如int、String等),也可以是自定义的Java对象。MyBatis会根据查询结果的列名和resultType的类型进行自动映射。示例代码如下:
xml
<select id="getUser" resultType="com.example.User">
SELECT * FROM users WHERE id = #{id}
</select>
resultType指定了查询结果的类型为com.example.User,MyBatis会将查询结果自动映射到User对象中。
parameterType
:parameterType
用于指定SQL语句的参数类型。它可以是Java的基本数据类型、Java对象或者是一个Map。示例代码如下:
java
<insert id="insertUser" parameterType="com.example.User">
INSERT INTO users (id, name, age) VALUES (#{id}, #{name}, #{age})
</insert>
parameterType指定了插入语句的参数类型为com.example.User,MyBatis会将User对象的属性值作为参数传递给SQL语句。
id
:id用于唯一标识映射文件(或注解)中的语句。它是一个字符串,可以自定义命名,用于在代码中调用对应的SQL语句。示例代码如下:
xml
<select id="getUserById" resultType="com.example.User">
SELECT * FROM users WHERE id = #{id}
</select>
UserMapper.xml文件
xml
<?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.miaow.mybatis.mapper.UserMapper">
<!--
resultMap:设置自定义映射
属性:
id:表示自定义映射的唯一标识
type:查询的数据要映射的实体类的类型
子标签:
id:设置主键的映射关系
result:设置普通字段的映射关系
association:设置多对一的映射关系
collection:设置一对多的映射关系
属性:
property:设置映射关系中实体类中的属性名
column:设置映射关系中表中的字段名
-->
<resultMap id="userMap" type="User">
<!-- 实际山和我们数据库字段别名差不多-->
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="username" column="username"></result>
<result property="sex" column="sex"></result>
<association property="book" javaType="Book">
<id property="uid" column="uid"></id>
<result property="book" column="bookName"></result>
<result property="cool" column="cool"></result>
</association>
</resultMap>
<!-- 根据resultMap获取相关数据-->
<select id="getUserById" resultMap="userMap" parameterType="int">
select * from user where id = #{id};
</select>
<!-- 管理其他表一对一查询 -->
<select id="getUserBookById" resultMap="userMap" parameterType="int">
select a.*,b.uid as uid,b.book as bookName ,b.cool as cool from user a
left join book b on a.id = b.uid
where a.id = #{id}
</select>
<!-- 插入单条数据
* useGeneratedKeys:设置使用自增的主键
* keyProperty:因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参数user对象的某个属性中
-->
<insert id="insertUser" parameterType="com.miaow.mybatis.bean.User" useGeneratedKeys="true" keyProperty="id" >
insert into user values(#{id},#{username},#{name},#{sex})
</insert>
<!-- 更新数据 -->
<update id="updateUser" parameterType="com.miaow.mybatis.bean.User">
update user set name = #{user.name} where id = #{user.id}
</update>
<!-- 删除单条数据-->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
<!-- 批量删除数据-->
<delete id="deleteUserBatch" parameterType="java.lang.String">
delete from user where id in (${ids})
</delete>
<!-- 根据ID查询相关数据-->
<select id="selectUser" resultType="com.miaow.mybatis.bean.User">
select * from user where id = #{user.id}
</select>
<!-- 查询数据库所有数据-->
<select id="selectAll" resultType="com.miaow.mybatis.bean.User">
select * from user
</select>
<select id="getUserToMap" resultType="java.util.Map" parameterType="int">
select * from user where id = #{id};
</select>
<select id="get100UserToMap" resultType="java.util.Map">
select * from user limit 100;
</select>
<select id="get100UserToMap2" resultType="java.util.Map">
select * from user limit 100;
</select>
<select id="selectUserLike" resultType="com.miaow.mybatis.bean.User"
parameterType="com.miaow.mybatis.bean.User">
select * from user where username like "%" #{user.username} "%"
</select>
<!-- 动态设置表名查询数据 -->
<select id="selectUserByTableName" resultType="com.miaow.mybatis.bean.User"
parameterType="java.lang.String">
select * from ${tableName} limit 100
</select>
</mapper>
我们根据上述的这个XML文件进行配置进行讲解:
MyBatis实现简单的增删改查也会实现MyBatis实现一些相对复杂的查询功能,其中包括查询List集合,查询一个实体类对象,以及查询单个数据,查询单条为Map的集合和多条Map的集合。
简单的新增
xml
<insert id="insertUser" parameterType="com.miaow.mybatis.bean.User" useGeneratedKeys="true" keyProperty="id" >
insert into user values(#{id},#{username},#{name},#{sex})
</insert>
我们通过SQL语句和Xml的配置文件写入SQL,但是不知道眼尖的同学看到没有,这里边我写了插入id,实际上是我架构表的时候,没有使用自增,这算是我的锅 ,如果你配置了自增,我们有没有发现useGeneratedKeys="true" keyProperty="id"
这个语句?
useGeneratedKeys
:设置使用自增的主键,默认为False。
我们在插入数据的时候,我们有时候需要直接插入数据的时候,这个时候我们可能不知道我们插入的主键id是多少
这个时候我们只需要配置 useGeneratedKeys="true" keyProperty="id" 然后我们就可以直接拿到我们插入数据的主键id,比如
int value = userMapper.insertUser(user); int id = userVo.getId();
//获取插入数据后的主键id
keyProperty
:因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参数user对象的某个属性中,比如我上面的是绑定的id,那么Mybatis就将返回的id值存入到实体类的与之相同的字段中。
删除单条数据
xml
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
删除多条数据
xml
<!-- 批量删除数据-->
<delete id="deleteUserBatch" parameterType="java.lang.String">
delete from user where id in (${ids})
</delete>
java
public void test8() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
String i = "5,6,7,8,9";
int V = userMapper.deleteUserBatch(i);
if(V > 0){
System.out.println("success");
}else {
System.out.println("fail");
}
}
查询一个实体类对象
java
User getUserById(@Param("id") int id);
xml
<select id="getUserById" resultType="com.miaow.mybatis.bean.User">
select * from t_user where id = #{id}
</select>
${}和#{}
MyBatis获取参数值的两种方式: ${}和#{}
${}
的本质就是字符串拼接,#{}
的本质就是占位符赋值
#{}
:#{}
是预编译的占位符,它会将参数值作为参数对象的属性值进行处理,并使用预编译语句来执行数据库操作。这种方式可以提供更好的系统安全性,因为参数值会被自动转义,从而防止SQL注入攻击。使用#{}可以有效地防止恶意用户通过参数值注入恶意的SQL代码。
${}
:${}
是字符串替换的占位符,它会将参数值直接替换到SQL语句中。这种方式更加灵活,可以在SQL语句中使用动态的表名、列名或其他字符串。然而,使用${}
也带来了一些安全风险,因参数值不会被自动转义,可能会导致SQL注入攻击。因此,使用${}
时需要确保参数值的安全性,例如通过输入验证或白名单过滤来防止恶意输入。
${}
使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号 ;
但是#{}
使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号
MyBatis中建议使用#{}
,原因在于其可以预防SQL注入,而${}
无法预防SQL注入
特殊SQL的执行:模糊查询,批量删除,动态设置表名,添加功能获取自增的主键
自定义映射
驼峰配置
主要为了解决java字段和数据库字段不一致问题。我们有两种方式,一种是自定义映射,一种是我们在MyBatis中配置驼峰命名的规则的自动映射。
xml
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
MyBatis的全局配置文件中开启驼峰命名规则的自动映射。通过设置mapUnderscoreToCamelCase
属性为true,MyBatis会自动将数据库表的下划线命名转换为Java对象的驼峰命名。
自定义映射resultMap,多对一和一对多映射关系处理
resultMap:设置自定义映射
属性:
id:表示自定义映射的唯一标识
type:查询的数据要映射的实体类的类型
子标签:
id:设置主键的映射关系
result:设置普通字段的映射关系
association:设置多对一的映射关系
collection:设置一对多的映射关系
属性:
property:设置映射关系中实体类中的属性名
column:设置映射关系中表中的字段名
xml
<resultMap id="userMap" type="User">
<!-- 实际山和我们数据库字段别名差不多-->
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="username" column="username"></result>
<result property="sex" column="sex"></result>
<association property="book" javaType="Book">
<id property="uid" column="uid"></id>
<result property="book" column="bookName"></result>
<result property="cool" column="cool"></result>
</association>
</resultMap>
自定义设置表名
xml
<!-- 动态设置表名查询数据 -->
<select id="selectUserByTableName" resultType="com.miaow.mybatis.bean.User"
parameterType="java.lang.String">
select * from ${tableName} limit 100
</select>
java
/**动态设置表名查询数据 可以通过@Param注解标识mapper接口中的方法参数此时,会将这些参数放在map集合中,以@Param注解的value属性值为键,以参数为值;*/
List<User> selectUserByTableName(@Param("tableName") String tableName);
java
// 动态设置表名查询数据
@Test
public void test9() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
//根据我们传入的表名查询对应的表信息
List<User> users = userMapper.selectUserByTableName("user");
for (User user : users) {
System.out.println(user);
}
}
测试类
java
public class UserTest {
@Resource
private UserService userService;
//插入单条数据
@Test
public void test() throws IOException {
//仅仅属于Mybatis框架的相关知识解决相关问题
//首先读取Mybatis配置文件
InputStream is = Resources.getResourceAsStream("mybatis.xml");
//创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//创建SqlSession
//第一个参数为是否自动提交,true为自动提交,false为手动提交,默认为false
//SqlSession对象,此时通过sqlSession对象所操作的sql都会提交
SqlSession session = sqlSessionFactory.openSession(true);
//通过sqlSession对象获取mapper接口对象
UserMapper userMapper = session.getMapper(UserMapper.class);
//执行sql,插入数据的时候,我做了一个操作就获取主键的操作,调用的事Mybatis的主键回调功能
int i = userMapper.insertUser(new User(1,"miaow","罗小黑","1"));
if(i > 0){
System.out.println("success");
}else {
System.out.println("fail");
}
//提交事务
//session.commit();
//关闭session
session.close();
}
//查询表中所有数据
@Test
public void test2() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
List<User> users = userMapper.selectAll();
if(users == null && users.size() == 0){
System.out.println("你查询的表无数据");
return;
}
for (User user : users) {
System.out.println(user);
}
session.close();
}
//根据ID查询相关数据
@Test
public void test3() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = new User();
user.setId(82);
User findById = userMapper.selectUser(user);
System.out.println(findById);
}
//查询单条数据
@Test
public void findByIdData() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.getUserById(86);
System.out.println(user);
}
//查询单条数据为map集合
@Test
public void test4() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
Map<String, Object> userToMap = userMapper.getUserToMap(520);
System.out.println(userToMap);
}
//查询前100条数据并将数据转换为Map集合
@Test
public void test5() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
List<Map<String,Object>> userToMapList = userMapper.get100UserToMap();
for (Map<String, Object> map : userToMapList) {
System.out.println(map);
}
}
//查询前100条数据并将数据转换为Map集合方式2
@Test
public void findData() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
Map<Integer, User> map = userMapper.get100UserToMap2();
Set<Integer> integers = map.keySet();
for (Integer integer : integers) {
System.out.println(map.get(integer));
}
}
//删除单条数据
@Test
public void test6() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
int i = userMapper.deleteUser(82);
if(i > 0){
System.out.println("success");
}else {
System.out.println("fail");
}
}
//批量删除数据
@Test
public void test8() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
String i = "5,6,7,8,9";
int V = userMapper.deleteUserBatch(i);
if(V > 0){
System.out.println("success");
}else {
System.out.println("fail");
}
}
//模糊查询
@Test
public void test7() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = new User();
user.setUsername("K");
List<User> users = userMapper.selectUserLike(user);
for (User user1 : users) {
System.out.println(user1);
}
}
// 动态设置表名查询数据
@Test
public void test9() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
List<User> users = userMapper.selectUserByTableName("user");
for (User user : users) {
System.out.println(user);
}
}
//更新表中数据
@Test
public void test10() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = new User();
user.setId(58);
user.setName("罗小黑");
int i = userMapper.updateUser(user);
if(i > 0){
System.out.println("success");
}else {
System.out.println("fail");
}
}
// association一对一联查
@Test
public void test11() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession(true);
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.getUserBookById(520);
System.out.println(user);
}
}