一、创建Mybatis的项目
Mybatis 是⼀个持久层框架, 具体的数据存储和数据操作还是在MySQL中操作的, 所以需要添加MySQL驱动
1.添加依赖
或者 手动添加依赖
<!--Mybatis 依赖包--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.4</version></dependency><!--mysql驱动包--><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency>
项⽬⼯程创建完成后,⾃动在pom.xml⽂件中,导⼊Mybatis依赖和MySQL驱动依赖
版本会随着SpringBoot 版本发⽣变化
SpringBoot 3.X对⽤MyBatis版本为3.X
对应关系参考:Introduction – mybatis-spring-boot-autoconfigure
2.配置常见的数据库信息
这是常见关于Mybatis的配置信息,大家可以自取
csdn暂时还不支持yml文件,这是 yml 文件:
spring:datasource: # 配置数据库名url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: root #数据库用户password: root #密码driver-class-name: com.mysql.cj.jdbc.Driver# 设置 Mybatis 的 xml 保存路径
mybatis: mapper-locations: classpath:mapper/*Mapper.xmlconfiguration: # 配置打印 MyBatis 执行的 SQLlog-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true #自动驼峰转换
前提是有这样的一个数据库
那么这里提供一个数据库:
-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;-- 使用数据数据
USE mybatis_test;-- 创建表[用户表]
DROP TABLE IF EXISTS user_info;
CREATE TABLE `user_info` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`username` VARCHAR ( 127 ) NOT NULL,`password` VARCHAR ( 127 ) NOT NULL,`age` TINYINT ( 4 ) NOT NULL,`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-女 0-默认',`phone` VARCHAR ( 15 ) DEFAULT NULL,`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; -- 添加用户信息
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );-- 创建文章表
DROP TABLE IF EXISTS article_info;CREATE TABLE article_info (id INT PRIMARY KEY auto_increment,title VARCHAR ( 100 ) NOT NULL,content TEXT NOT NULL,uid INT NOT NULL,delete_flag TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',create_time DATETIME DEFAULT now(),update_time DATETIME DEFAULT now()
) DEFAULT charset 'utf8mb4';-- 插入测试数据
INSERT INTO article_info ( title, content, uid ) VALUES ( 'Java', 'Java正文', 1 );
这样一个表
3.写对应的对象
一般写在model文件夹下
@Data
public class UserInfo {private Integer id;private String username;private String password;private Integer age;private Integer gender;private String phone;//数据库用下划线连接单词,java直接用小驼峰private Integer deleteFlag;private Date createTime;private Date updateTime;}
4.写持久层代码
一般写在mapper文件夹下,或者Dao
@Mapper
public interface UserInfoMapper {//查询所有用户的信息@Select("select * from user_info")List<UserInfo> selectAll();
}
5.单元测试
在对应的mapper接口下,右击
@SpringBootTest
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid selectAll() {userInfoMapper.selectAll().forEach(x -> System.out.println(x));//等同于
// List<UserInfo> userInfos = userInfoMapper.selectAll();
// for (UserInfo userInfo : userInfos) {
// System.out.println(userInfo);
// }}
}
结果:
二、Mybatis的基本操作
1.日志打印
2.传递单个参数
通过 #{……} 传递 参数
@Mapper
public interface UserInfoMapper {// 只有一个参数的时候这里写什么名字无所谓@Select("select * from user_info where id = #{id}")UserInfo selectUserById(Integer id);
}
单元测试:
@SpringBootTest
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid selectUserById() {System.out.println(userInfoMapper.selectUserById(2));}
}
结果:
3.传递多个参数
3种方法
方法1:
标签 和 方法 中的名字一样
方法2:
它给方法的每个形参取了别名,例如第一个param1 第二个 param2
方法3:
使用@Param("……"),和 标签中的 #{……}对应
@Mapper
public interface UserInfoMapper {// @Select("select * from user_info where id = #{id} and gender = #{gender}") 方法1 推荐// @Select("select * from user_info where id = #{param2} and gender = #{param1}") 方法2 不推荐// @Select("select * from user_info where id = #{id2} and gender = #{gender2}") 错误//@Select("select * from user_info where id = #{id2} and gender = #{gender2}") // 方法3 推荐List<UserInfo> selectUserByIdAndGender(@Param("id2") Integer id,@Param("gender2") Integer gender);}
单元测试:
@SpringBootTest
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid selectUserByIdAndGender() {List<UserInfo> userInfos = userInfoMapper.selectUserByIdAndGender(3, 1);System.out.println(userInfos);}
}
结果:
返回的参数可以是对象,也可以是集合类:
当我们知道数据库中对应的参数只有一个时,可以用类接收,但是最好用集合,万一他人增加了符号相同条件的数据,一个类就装不下。
4.查(Select)
查询之前已经都写到了,就不再写了。
发现这样的一个问题:
数据库的规范是单词之间用下划线分割,java的变量规范是小驼峰命名。这就导致了属性对应不上导致为null
解决办法,我先讲最推荐的:
4.1 开启驼峰命名
在yml或者properties文件中设置:
# 设置 Mybatis 的 xml 保存路径
mybatis:mapper-locations: classpath:mapper/*Mapper.xmlconfiguration: # 配置打印 MyBatis 执行的 SQLlog-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true #自动驼峰转换
4.2 起别名
@Mapper
public interface UserInfoMapper {@Select("select id, username, password, age, gender, phone, delete_flag as deleteFlag, " +"create_time as createTime, update_time as updateTime from user_info")List<UserInfo> selectAll2();}
即便是不用起别名也不建议用 select * , 就应该用到哪一列写哪一列,即便是所有的列都需要也这么写,因为更加规范。
4.3 结构映射
4.3.1 @Results 和 @Result
@Mapper
public interface UserInfoMapper {// @Select("select id, username, password, age, gender, phone, delete_flag as deleteFlag, " +
// "create_time as createTime, update_time as updateTime from user_info")@Results({@Result(column = "delete_flag", property = "deleteFlag"),@Result(column = "create_time", property = "createTime"),@Result(column = "update_time", property = "updateTime")})@Select("select id, username, password, age, gender, phone, delete_flag, create_time, update_time from user_info")List<UserInfo> selectAll2();
}
这样比起别名麻烦呀,那么真实用法是这样:
4.3.2 @ResultMap
5.增(Insert)
5.1传递对象
方法一:
@Mapper
public interface UserInfoMapper {@Insert("insert into user_info (username, `password`, age, gender) values (#{username},#{password},#{age},#{gender})")Integer insertUser(UserInfo userInfo);}
Mapper层
@SpringBootTest
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid insertUser() {UserInfo userInfo = new UserInfo();userInfo.setUsername("张三");userInfo.setPassword("123445");userInfo.setAge(19);userInfo.setGender(0);userInfoMapper.insertUser(userInfo);}}
成功:
方法二:
@Mapper
public interface UserInfoMapper {@Insert("insert into user_info (username, `password`, age, gender)" +"values (#{userInfo.username},#{userInfo.password},#{userInfo.age},#{userInfo.gender})")Integer insertUserByParam(@Param("userInfo") UserInfo userInfo);
}
@SpringBootTest
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid insertUserByParam() {UserInfo userInfo = new UserInfo();userInfo.setUsername("李四");userInfo.setPassword("jaba213");userInfo.setAge(19);userInfo.setGender(0);userInfoMapper.insertUser(userInfo);}
}
6.删(Delete)
删除的时候一般使用id删除
假设我们现在是pdd的员工,我们下单了一个商品但是还没有付钱,那么此时我们就需要拿到这个订单的id,如果在10分钟内不付钱,我们就删除这个订单。
那么我们就需要在插入之后拿到id,可以用这个注解:
6.1 @Options
@Mapper
public interface UserInfoMapper {@Delete("delete from user_info where id = #{id}")Integer delete(Integer id);@Options(useGeneratedKeys = true, keyProperty = "id")@Insert("insert into user_info (username, `password`, age, gender)" +"values (#{userInfo.username},#{userInfo.password},#{userInfo.age},#{userInfo.gender})")Integer insertUserByParam(@Param("userInfo") UserInfo userInfo);}
单元测试:
@SpringBootTest
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid insertUserByParam() {UserInfo userInfo = new UserInfo();userInfo.setUsername("wangmaz");userInfo.setPassword("54231");userInfo.setAge(19);userInfo.setGender(0);//返回影响的行数Integer result = userInfoMapper.insertUserByParam(userInfo);// 通过getId()获取 System.out.println("执行结果" + result + " ,id : " + userInfo.getId());}
结果:
那么拿到数据你想用这个id干什么自己处理就好了
普通的删除:
@Mapper
public interface UserInfoMapper {@Delete("delete from user_info where id = #{id}")Integer delete(Integer id);}
单元测试:
@SpringBootTest
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid delete() {
// 删除id为11的数据userInfoMapper.delete(11);}
}
运行前:
运行后:
7.改(Update)
@Mapper
public interface UserInfoMapper {@Update("update user_info set password = #{password} where id = #{id}")Integer update(Integer id, String password);
}
@Mapper
public interface UserInfoMapper {@Update("update user_info set password = #{password} where id = #{id}")Integer update(Integer id, String password);
}
修改前:
修改后 :
三、报错信息
看到这样的报错“密码错误”,直接去看配置信息
数据库返回结构太多,方法定义的返回结果不匹配
标签参数和方法参数不匹配