目录
四、引入mysql、springboot整合mybatis的依赖
写在前面:
1、 mybatis 是一款作用于持久层的半自动映射框架。
2、mybatis对JDBC的代码进行封装。
3、可以基于XML文件和注解来映射java实体类和数据库列的关系。
传送门:
使用IDEA新建一个springboot项目_听钱塘信起的博客-CSDN博客
一、环境
IDEA 2021.3
mysql 8.x
maven 3.8.6
java 17
二、准备数据库脚本及数据
创建SQL数据库:
create database boot_mybatis;
use boot_mybatis;
创建一张用户表(t_user):
-- boot_mybatis.t_user definition
CREATE TABLE `t_user` (
`u_id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户登录名',
`email` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '邮箱',
`password` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '密码',
`birth` date DEFAULT NULL COMMENT '生日',
`gender` bigint NOT NULL DEFAULT '2' COMMENT '性别,0:男,1:女,2:保密',
PRIMARY KEY (`u_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=67 DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC;
数据:
INSERT INTO boot_mybatis.t_user (username, email, password, birth, gender) VALUES('张三', '12345@qq.com', '123', '2022-10-1', 2);
三、创建对应表的实体类
@Data
public class IUser {
private String username;
private String email;
private String password;
private Date birth;
private int gender;
}
四、引入mysql、springboot整合mybatis的依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
五、配置连接数据库的参数
spring:
datasource:
url: jdbc:mysql://localhost:3308/boot_mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&AllowPublicKeyRetrieval=True
username: root
password: root
mybatis:
mapperLocations: mapper/*.xml
六、查询所有的用户
步骤:新建查询用户的接口----->绑定xml-->测试
6.1、新建查询在接口里新建查询方法:
新建一个包 com.example.demo.infra.mapper、在该目录下新建一个接口IUserMapper、
在该接口下新建一个获取所有用户的方法:List<IUser> selectUser();
package com.example.demo.infra.mapper;
import com.example.demo.domain.entity.IUser;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface IUserMapper {
/**
* 获取所有用户
* @return 用户List
*/
List<IUser> selectUser();
}
6.2、mapper接口方法的实现:
6.2.1 基于注解实现+SQL【了解即可、灵活度不高】
/** * 获取所有用户 * @return 用户List */ @Select("SELECT user_name, email, pass_word, birth, gender FROM t_user") List<IUser> selectAllUser();
单元测试代码:
注入IUserMapper,由userMapper调用selectAllUser()方法;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) public class DemoApplicationTests { @Autowired private IUserMapper userMapper; @Test public void getUser(){ List<IUser> userList = userMapper.selectAllUser(); System.err.println(userList.toString()); } }
执行sql及结果
使用:@Insert、@Update、@Select、@Delete +对应的SQL;
6.2.2基于xml实现【常用、重点】
在resource目录下新建mapper目录、在目录下新建IUserMapper.xml文件,声明是mybatis的配置通过namespace绑定对应xxxMapper,通过id绑定对应方法;
<?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.demo.infra.mapper.IUserMapper">
<select id="selectUser" resultType="com.example.demo.domain.entity.IUser">
SELECT username, email, password, birth, gender FROM t_user;
</select>
</mapper>
标签的属性介绍:
namespace绑定mapper接口的全限定名;
id 是mapper接口方法里的方法名称;
resultType 是输出映射类型;
当前项目结构如下:
6.3、测试
6.3.1 单元测试
流程:在单元测试类下注入IUserMapper,再新建一个测试方法,注入IUserMapper,由userMapper调用getUser()方法即可。
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class DemoApplicationTests {
@Autowired
private IUserMapper userMapper;
@Test
public void getUser(){
List<IUser> userList = userMapper.selectUser();
System.err.println(userList.toString());
}
}
会在控制台看到查询结果。
优化一、将执行的SQL打印在控制台
实际情况是不会直接将查询结果打印在控制台的、而是将执行的SQL、SQL执行结果以日志的形式输出。加上如下配置即可
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
效果:
优化二、使用resultMap对返回结果的字段进行映射
许多场景并不需要一张表对应一个实体类,也不需要一张表的一个字段对应一个属性。由此根据使用的地方不同区分为DTO、Query、VO、POJO等等。
为查询的结果和需要展示的字段可以一一对应,处理方式有:比如数据库里的字段是user_name,那建立实体类时需要映射为userName;否则查出来的值为null或者报错;
1、把resultType,改为resultMap、在resultMap里做字段映射。
要是实体类属性和表字段一致的可以不用映射。resultMap还有的一对多和多对多的用法。
2、继续使用resultType、但新建一个实体,在实体里将字段和查出的字段一一对应,并且开启驼峰映射。
mybatis:
mapperLocations: mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #日志输出
map-underscore-to-camel-case: true #开启驼峰映射
6.3.2 通过接口测试
流程:
因为需要返回Json数据,所有contrller层用@RestController注解
service的对应实现类上加上@Service注解
当前目录结构如下
内容如下:
1、新建一个一个IUserController类,注入IUserService,定义一个getAllUser方法,拦截Get请求、拦截路径是/getAllUser,返回数据由userService调用获取全部用户的方法获取;
@RestController
public class IUserController {
@Autowired
private IUserService userService;
@GetMapping("/getAllUser")
public List<IUser> getAllUser(){
return userService.selectUser();
}
}
2、新建IUserService接口、定义获取全部用户的方法;由他的实现类去调用mapper方法。
/**
* 获取所有用户
* @return 用户List
*/
List<IUser> selectUser();
3、新建IUserServiceImpl类、用来实现接口IUserService;注入IUserMapper,实现接口里的方法。
@Service
public class IUserServiceImpl implements IUserService {
@Autowired
private IUserMapper userMapper;
/**
* 获取所有用户
*
* @return 用户List
*/
@Override
public List<IUser> selectUser() {
return userMapper.selectUser();
}
}
项目启动后访问IUserController的接口、我是用postman测试的、也可以在浏览的地址栏直接输入URL
本文涉及的几个注解:
@Component
实现普通bean的注入spring容器、由于作用地方不一样衍生如下三个注解 :
@Controller controller层
@Repository dao层
@Service service层
@mapper
被上周注解标注后、该类的生命周期由spring托管、我们需要用的时直接往spring容器里取就成;
@Autowired 用来装配对象的。默认类型装配。
@ResponseBody 表示将返回的java对象转为json对象
@RestController 作用等同于@Controller +@ResponseBody
@MapperScan mapper包扫描+包的全限定名
七、增删改查
以下操作均以单元测试的方式完成测试:
步骤均是:
1、在IUserMapper接口里定义方法。
2、IUserMapper.xml绑定对应方法、编写对应SQL
3、编写单元测试
7.1、新增一个用户:
7.1.1 新增保存用户的方法;
/** * 保存用户 * @param user * @return */ int savaUser(IUser user);
7.1.2 绑定xml
<insert id="savaUser" parameterType="com.example.demo.domain.entity.IUser" > INSERT INTO t_user (user_name, email, password, birth, gender) VALUES(#{userName}, #{email},#{password} , #{birth}, #{gender}); </insert>
#{}表示占位参数等价于" ?"
7.1.3 编写测试方法并测试
@Test public void saveUser(){ IUser user = new IUser(); user.setUserName("李白"); user.setPassWord("456"); user.setEmail("1234@qq.com"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date date = new Date(2022,10,1); dateFormat.format(date); user.setGender(1); user.setBirth(date); int res = userMapper.savaUser(user); System.err.println("res:"+res); }
控制台查看执行的sql
查看数据库表中是否插入了此数据
此处与输入的日期不一致,源码里有些是+1900的结果、咱这儿只测试是否能保存成功。
7.2、删除一个用户:
7.2.1 新增删除根据ID删除用户接口
/** * 根据用户ID删除 * @param id * @return */ int delById(int id);
7.2.2 绑定XML文件
<delete id="delById" parameterType="integer"> DELETE FROM t_user WHERE u_id=#{id}; </delete>
7.2.3 编写测试类
@Test public void delById(){ userMapper.delById(72); }
没有对应ID,影响行数就是0;否则大于0
7.3、修改李白的生日为'2022-10-01'
要修改、先查询
(1)修改查询全部用户的方法【也可以直接新建一个条件查询方法】
/** * 获取所有用户 * @return 用户List */ List<IUser> selectUser(IUser user);
修改xml文件
<select id="selectUser" resultMap="userMap" parameterType="com.example.demo.domain.entity.IUser"> SELECT user_name, email, pass_word, birth, gender FROM t_user <where> <if test="userName !=null"> user_name = #{userName} </if> </where> </select>
(2) 定义一个修改用户信息的接口
/** * 修改用户信息 * @param user * @return */ int updateUser(IUser user);
7.3.2 绑定XML
<update id="updateUser"> UPDATE t_user SET email=#{email}, pass_word=#{passWord}, birth=#{birth}, gender=#{gender} WHERE user_name=#{userName}; </update>
7.3.3 编写测试类
要修改、先查询
@Test public void testUpdateUser() throws ParseException { // 查询姓名叫李白的用户 IUser queryUser = new IUser(); queryUser.setUserName("李白"); List<IUser> userList = userMapper.selectUser(queryUser); // 查询接口非空则更新第一天 if(!userList.isEmpty()){ // 此处更新第一条数据 IUser updateUser = userList.get(0); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date date = sdf.parse("2022-10-01"); updateUser.setBirth(date); int res = userMapper.updateUser(updateUser); System.err.println("res:"+res); } }
7.4、批量新增:
7.4.1 定义一个批量新增用户的接口
/** * 批量新增 * @return int */ int batchInsert(@Param("userList") List<IUser> userList);
7.4.2 绑定XML
<insert id="batchInsert" parameterType="java.util.List"> insert into t_user(user_name, email, pass_word, birth, gender) values <foreach collection="userList" item="user" separator=","> (#{user.userName}, #{user.email},#{user.passWord} , #{user.birth}, #{user.gender}) </foreach> </insert>
7.4.3 编写测试类
@Test public void testBatchInsert(){ List<IUser> userList = new ArrayList<>(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); IUser user = new IUser(); user.setUserName("李白"); user.setPassWord("456"); user.setEmail("1234@qq.com"); Date date = new Date(); dateFormat.format(date); user.setGender(1); user.setBirth(date); IUser user2 = new IUser(); user2.setUserName("李白"); user2.setPassWord("456"); user2.setEmail("1234@qq.com"); Date date2 = new Date(); dateFormat.format(date2); user2.setGender(1); user2.setBirth(date2); IUser user3 = new IUser(); user3.setUserName("李白"); user3.setPassWord("456"); user3.setEmail("1234@qq.com"); Date date3 = new Date(); dateFormat.format(date3); user3.setGender(1); user3.setBirth(date3); userList.add(user); userList.add(user2); userList.add(user3); int res = userMapper.batchInsert(userList); System.err.println("res:"+res); }
7.5、批量删除:
7.5.1 定义一个批量根据Id批量的接口
/** * 批量删除 * @return int */ int delByIds(@Param("ids") List<Integer> ids);
7.5.2 绑定XML
<delete id="delByIds"> DELETE FROM t_user WHERE u_id IN ( <foreach collection="ids" item="id" separator=","> #{id} </foreach> ) </delete>
7.5.3 编写测试类
@Test public void testDelByIds(){ ArrayList<Integer> list = new ArrayList<>(); list.add(74); list.add(75); list.add(76); list.add(90); userMapper.delByIds(list); }
小结:
关于<foreach>
节点:进入源码查看可配置的属性:collection :被遍历的对象
item:遍历得到的元素
separator:每个item之间元素的分隔符
另外三个用默认的就可()
批量修改结合批量插入和新增操作;
持续更新中。。。
查询结果一对多和多对多如何处理:
mybatis中 一对多(collection)、多对一(association)的一些处理方式
报错
错误:Failed to load ApplicationContext
解决·:需要引入mysql驱动jar包
错误:Invalid bound statement (not found): com.example.demo.infra.mapper.IUserMapper.XXX
需要指定xml文件的位置:
mybatis:
mapperLocations: mapper/*.xml
错误: No qualifying bean of type 'com.xxx.xxMapper' available:
解决:在对应的mapper文件加上@Mapper注解