【MyBatis】MyBatis入门学习

    技术2022-07-11  147

    – MyBatis入门学习–

    1. MyBatis简介

    MyBatisPlus官网:https://mp.baomidou.com/guide/

    2. 快速开始

    对于MyBatis的整合常常有三种方式,分别是:MyBatis+MP 、 Spring+MyBatis+MP 、 SpringBoot+MyBatis+MP。

    2.1 创建数据库以及表

    随便使用一个数据库和表都是可以的: CREATE DATABASE mybatis_plus CHARSET utf8; USE mybatis_plus; #创建用户表 CREATE TABLE USER ( id BIGINT(20) PRIMARY KEY NOT NULL COMMENT '主键', NAME VARCHAR(30) DEFAULT NULL COMMENT '姓名', age INT(11) DEFAULT NULL COMMENT '年龄', email VARCHAR(50) DEFAULT NULL COMMENT '邮箱', manager_id BIGINT(20) DEFAULT NULL COMMENT '直属上级id', create_time DATETIME DEFAULT NULL COMMENT '创建时间', CONSTRAINT manager_fk FOREIGN KEY (manager_id) REFERENCES USER (id) ) ENGINE=INNODB CHARSET=UTF8; #初始化数据: INSERT INTO USER (id, NAME, age, email, manager_id , create_time) VALUES (1087982257332887553, '大boss', 40, 'boss@baomidou.com', NULL , '2019-01-11 14:20:20'), (1088248166370832385, '王天风', 25, 'wtf@baomidou.com', 1087982257332887553 , '2019-02-05 11:12:22'), (1088250446457389058, '李艺伟', 28, 'lyw@baomidou.com', 1088248166370832385 , '2019-02-14 08:31:16'), (1094590409767661570, '张雨琪', 31, 'zjq@baomidou.com', 1088248166370832385 , '2019-01-14 09:15:15'), (1094592041087729666, '刘红雨', 32, 'lhm@baomidou.com', 1088248166370832385 , '2019-01-14 09:48:16');

    2.2 创建工程

    2.2.1 MyBatis + MP

    创建一个Maven项目不用选择骨架直接Next即可。

    导入依赖:MyBatis-plus(3.1.1)、Mysql驱动包、数据库连接池(Druid)、lombok(简化代码工具包)、junit(单元测试),slf4j(日志工具)、以及修改JDK版本的插件。

    <packaging>jar</packaging> <!--Mybatis-plus--> <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>3.1.1</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- jdk1.8 --> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build>

    2.3 创建子module(就是创建一个子module继承自父module)

    创建的子module会集成来自父module中的依赖的;又是可能不会及时生效需要刷新一下Maven便可以了。

    编写全局的Mybatis配置文件在resources文件夹下,如果新创建的子module文件夹不是对应的source root文件夹或者不是resource文件夹需要进行手动的设置。下面是具体设置的操作图以及Mybatis全局配置文件mybatis-config.xml文件的内容。

    mybatis-config.xml配置文件中的内容,mapper中配置的映射配置文件我创建在了与mybatis-config.xml文件夹同级的目录所以不需要在加上文件夹路径。

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!-- mybatis的主配置文件 --> <configuration> <!-- 配置环境 --> <environments default="mysql"> <!-- 配置mysql的环境--> <environment id="mysql"> <!-- 配置事务的类型--> <transactionManager type="JDBC"></transactionManager> <!-- 配置数据源(连接池) --> <dataSource type="POOLED"> <!-- 配置连接数据库的4个基本信息 --> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis_plus"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 --> <mappers> <mapper resource="UserMapper.xml"/> </mappers> </configuration> 创建数据库对应的实体类:由于使用了lombok插件所以简化了代码,不用写setter和getter方法以及toString方法。还可以使用注解生成空参构造和全参构造; @Data @NoArgsConstructor @AllArgsConstructor public class User { private Long id; private String name; private Integer age; private String email; private Long managerId; private Date createTime; } 编写UserMapper接口,定义里面的查询全部的抽象方法findAll; public interface UserMapper { List<User> findAll(); } 编写UserMapper映射配置文件: <?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"> <!--namespace中写上对应的Mapper接口所在位置--> <mapper namespace="com.lyp.mapper.UserMapper"> <!--resultType中写上对应返回值类型--> <select id="findAll" resultType="com.lyp.pojo.User"> select * from user; </select> </mapper> 在test中编写测试类进行测试: public class MybatisTest { @Test public void testFindAll() throws IOException { InputStream in = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); SqlSession sqlSession = factory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> userList = userMapper.findAll(); userList.forEach(System.out::println); } }

    2.3.3 Mybatis+MP实现查询User (使用Mybatis—Plus的方式)

    在Mybatis中整合Mybatis-Plus插件;

    **第一步:**将UserMapper继承BaseMapper,将拥有BaseMapper中定义的所有方法:

    /** * 使用Mybatis-Plus的方式进行查询 */ public interface UserMapper extends BaseMapper<User> { // List<User> findAll(); }

    **第二步:**使用MP中的MybatisSqlSessionFactoryBuilder进行构建:

    @Test public void testFindAll() throws IOException { InputStream in = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactoryBuilder builder = new MybatisSqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); SqlSession sqlSession = factory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); /*由于需要查询全部并且没有查询条件只需要传递一个null即可*/ List<User> userList = userMapper.selectList(null); userList.forEach(System.out::println); } **注意事项:**当我们数据库的表名称和实体类的名称不是一一对应的时候,将会报错。解决办法:使用@TableName(“数据表名称”) 。

    2.4 Spring + Mybatis + MP

    引入Spring框架,数据源、构建工作就交给了Spring管理了。

    2.4.1 创建子module

    Spring的整合就暂时没有做。。。。

    2.5 SpringBoot + Mybatis + MP整合使用

    2.5.1 创建一个SpringBoot项目

    创建一个SpringBoot项目

    2. 选择初始装备

    2.5.2 导入依赖

    导入相关的依赖 : <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.1.1</version> </dependency> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency>

    2.5.3 编写配置文件

    spring.application.name=mybatis_plus_spring_boot spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.username=root spring.datasource.password=root

    2.5.4 编写测试类

    @RunWith(SpringRunner.class) @SpringBootTest public class MybatisSpringBootTest { @Autowired private UserMapper userMapper; @Test public void findAll() { List<User> userList = userMapper.selectList(null); userList.forEach(System.out::println); } }

    3. 通用CRUD

    在前面,了解了通过继承BaseMapper就可以获取到各种各样的单表操作,接下来就是详细的使用这些操作:

    3.1 测试insert方法

    注意 : 如果在设置对象的值时不设置主键id的值,但是又想设置其为主键自增的,可以使用@TableId(type = IdType.Auto)在实体类的主键id上进行标注;

    测试insert方法: @Test public void insertTest() { User user = new User(); user.setAge(12); user.setCreateTime(new Date()); user.setEmail("123456@gmail.com"); user.setManagerId(123456L); user.setName("张三"); user.setId(123456L); int result = userMapper.insert(user); // 返回值是一个数据库库被影响的行数 System.out.println("result => " + result); System.out.println(user.getId());// 插入之后主键id会自动填充 }

    3.1 @TableField注解

    在MP中通过@Table注解可以指定字段的一些属性,常常解决的问题有两个:

    对象的属性名称和字段名称不一致的问题(非驼峰); @tableField(value = 数据库中的实际字段)对象的属性字段在表中不存在的问题。@tableField(exist = false)查询时不返回该字段的值@tableField(select = false) @Data @NoArgsConstructor @AllArgsConstructor public class User { //如果需要设置主键id增长策略 // @TableId(type = IdType.AUTO) // 设置主键自增 private Long id; private String name; // 当不想将某个字段查询出来的时候可以使用 @TableField(select = false) private Integer age; // 当实体类的属性名称与数据库的字段名称不一致的使用可以使用@TableField(value = 数据库中字段的名称) @TableField(value = "email") private String mail; private Long managerId; private Date createTime; // 当某个字段在数据库中不存在的时候需要进行声明 @TableField(exist = false) private String address; }

    3.2 更新操作

    在MP中,更新操作有两种,一种是根据id更新,另一种是根据条件进行更新;

    3.2.1 根据id进行更新

    1. 方法定义:

    blic void updateByIdTest() { User user = new User(); user.setId(123456L); user.setAge(166); user.setMail("123@Gmal.com"); int result = userMapper.updateById(user); System.out.println("====================" + result + "=================="); }

    3.2.2 根据条件进行更新

    **1. 方法定义:使用对象set的方式 **

    /** * 根据条件进行更新 */ @Test public void updateByWrapper() { User user = new User(); user.setAge(1000); user.setMail("1000@Gmail.com"); QueryWrapper<User> wrapper = new QueryWrapper<User>(); wrapper.eq("manager_id","1087982257332887553"); int result = userMapper.update(user, wrapper); System.out.println(result); }

    **2. 方法定义:在条件中set数据库字段对应的值 **

    /** * 根据条件进行更新的操作02 */ @Test public void updateByWrapper02() { UpdateWrapper<User> wrapper = new UpdateWrapper<User>(); wrapper.set("age", 100).set("email", "666888@qq.com") // 需要更新的字段 .eq("manager_id", "1087982257332887553");// 更新的条件 int result = userMapper.update(null, wrapper); System.out.println("=======操作结果========" + result); }

    3.2.3 根据id进行删除

    /** * 根据id进行删除 */ @Test public void deleteById() { int result = userMapper.deleteById(12345678L); System.out.println("==========删除执行结果=========" + result); }

    3.2.4 根据map条件进行删除

    /** * 根据Map条件删除数据 , 多个条件之间使用and连接 */ @Test public void deleteByMap() { Map<String, Object> map = new HashMap<>(); map.put("manager_id", "123456"); map.put("age", 12); int result = userMapper.deleteByMap(map); System.out.println("==========执行结果==========" + result); }

    3.2.5 根据QueryWrapper条件进行删除

    /** * 根据条件进行删除 QueryWrapper */ @Test public void deleteByQueryWrapper() { // 方法一 : QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("name", "张三").eq("id", "1234567"); int result = userMapper.delete(wrapper); System.out.println("=========执行结果=========" + result); }

    3.2.6 根据id进行批量删除

    /** * 根据id进行批量的删除操作 */ @Test public void testBatchId() { int result = userMapper.deleteBatchIds(Arrays.asList(1234567L, 1234568L)); System.out.println("==========执行结果============" + result); }

    3.3 查询操作

    3.3.1 根据主键id进行查询

    /** * 根据主键id进行查询 */ @Test public void testSelectById() { User user = userMapper.selectById(123456); System.out.println(user); }

    3.3.2 根据id进行批量查询

    /** * 根据id进行批量查询 */ @Test public void testSelectByBatchId() { List<User> userList = userMapper.selectBatchIds(Arrays.asList(123456L, 1087982257332887553L)); userList.forEach(System.out::println); }

    3.3.3 根据条件查询一个selectOne

    /** * 根据条件查询一个 */ @Test public void testSelectOne() { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("name","刘红雨"); User user = userMapper.selectOne(wrapper); System.out.println(user); }

    3.3.4 根据条件查询数据的条数

    /** * 根据条件查询数据的条数 */ @Test public void testSelectCount() { QueryWrapper wrapper = new QueryWrapper(); //查询用户年龄大于30岁的 wrapper.gt("age", 30); Integer userCount = userMapper.selectCount(wrapper); System.out.println("====> UserCount ===> " + userCount); }

    3.3.5 查询数据列表 也可以根据条件进行查询

    /** * 查询列表 可以根据条件进行查询 */ @Test public void testSelectList() { QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.like("name", "张"); List<User> userList = userMapper.selectList(wrapper); userList.forEach(System.out::println); }

    3.3.6 分页查询 selectPage

    需要使用分页首先需要配置一个分页插件; /** * 声明一个分页插件的配置类 */ @Configuration public class PaginationInterceptor { @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } } 分页查询测试 : /** * 使用分页查询 */ @Test public void testSelectPage() { QueryWrapper wrapper = new QueryWrapper(); wrapper.like("name", "张"); Page<User> page = new Page<>(1, 2); IPage iPage = userMapper.selectPage(page, wrapper); long current = iPage.getCurrent(); System.out.println("当前页 ====> " + current); long size = iPage.getSize(); System.out.println("每页显示条数 === > " + size); long pages = iPage.getPages(); System.out.println("总共 " + pages + "页"); List userList = iPage.getRecords(); userList.forEach(System.out::println); long total = iPage.getTotal(); System.out.println("数据总数 == > " + total); }

    3.4 SQL注入的原理

    。。。。。

    4. 配置

    4.1 基本配置

    4.1.1 configLocation

    Mybatis配置文件位置,如果您有单独的Mybatis配置,请将其路径配置到configLocation中,MybatisConfiguration的具体内容请参考Mybatis官方文档;

    SpringBoot中的配置 :

    # 配置Mybatis-Plus额外的配置文件 指定全局配置文件 # mybatis-plus.config-location=classpath:mybatis-config.xml

    4.1.2 MapperLocations

    首先创建一个文件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.lyp.mapper.UserMapper"> <select id="findById" resultType="com.lyp.pojo.User"> select * from user where id = #{id}; </select> </mapper> 在application.propertis配置文件中配置Mapper.xml文件的位置 #classpath之后有 * 表示 可以扫描所有依赖中的classpath下的xml文件 如果没有*表示只扫描当前resources下的xml #指定mapper.xml文件的位置 mybatis-plus.mapper-locations=classpath*:mybatis/*.xml 在Mapper接口中新增方法findById User findById(Long id); 编写测试用例进行测试 /** * 测试自定义的findById */ @Test public void testFindById() { User user = userMapper.findById(123456L); System.out.println(user); }

    4.1.3 typeAliasespackage

    Mybatis别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在Mapper对应的xml文件中可以直接使用类名,而不用使用全限定的类名(即XML调用的时候不包含包名)。

    Springboot:

    # 配置别名包扫描路径 ; 实体对象的扫描包 mybatis-plus.type-aliases-package=com.lyp.pojo

    l文件的位置

    #classpath之后有 * 表示 可以扫描所有依赖中的classpath下的xml文件 如果没有*表示只扫描当前resources下的xml #指定mapper.xml文件的位置 mybatis-plus.mapper-locations=classpath*:mybatis/*.xml 在Mapper接口中新增方法findById User findById(Long id); 编写测试用例进行测试 /** * 测试自定义的findById */ @Test public void testFindById() { User user = userMapper.findById(123456L); System.out.println(user); }

    4.1.3 typeAliasespackage

    Mybatis别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在Mapper对应的xml文件中可以直接使用类名,而不用使用全限定的类名(即XML调用的时候不包含包名)。

    [外链图片转存中…(img-Ehri7Xcp-1593581578416)]

    Springboot:

    # 配置别名包扫描路径 ; 实体对象的扫描包 mybatis-plus.type-aliases-package=com.lyp.pojo
    Processed: 0.010, SQL: 9