[[JDBC链接&关闭]] [[spring]]
MyBatis 什么是MyBatis MyBatis是一款优秀的持久层框架 ,用于简化JDBC开发
持久层
负责将数据保存到数据库的那一层代码
javaEE三层架构:表现层,业务层,持久层
框架
半成品 软件,是一套可重用的,通用的,软件基础代码模型
在框架的基础之上构建软件编写更加高校,规范,通用,可扩展
快速入门
创建user表,添加数据 –> 对应pojo类
创建模块,导入坐标
编写mybatis核心配置文件 –> 替换链接信息,解决硬编码问题
编写SQL映射文件 –> 统一管理sql语句,解决硬编码问题
编码
定义pojo类
加载核心配置文件,获取SqlSessionFactory对象
获取SqlSession对象,执行SQL语句
释放资源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 mybatis-config <?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" > <configuration > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.cj.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql://localhost:3306/bookta" /> <property name ="username" value ="root" /> <property name ="password" value ="csh20011103" /> </dataSource > </environment > </environments > <mappers > 添加映射 <mapper resource ="UserMapper.xml" /> </mappers > </configuration >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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为空间,名字随便写,之后访问的时候用name.语句id即可 <mapper namespace ="name" > id为唯一值,resultType对应返回的类型 <select id ="selectAll" resultType ="org.example.pojo.User" > select * from bookta; </select > </mapper >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 该文件对应用户数据,位于pojo文件夹下 package org.example.pojo;public class User { private String isbn; private String title; private String type; private double price; public String getIsbn () { return isbn; } public void setIsbn (String isbn) { this .isbn = isbn; } public String getTitle () { return title; } public void setTitle (String title) { this .title = title; } public String getType () { return type; } public void setType (String type) { this .type = type; } public double getPrice () { return price; } public void setPrice (double price) { this .price = price; } @Override public String toString () { return "User{" + "isbn='" + isbn + '\'' + ", title='" + title + '\'' + ", type='" + type + '\'' + ", price=" + price + '}' ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 测试用例 package org.example;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.example.pojo.User;import org.example.service.BookService;import org.example.service.impl.BookServiceImpl;import java.io.IOException;import java.io.InputStream;import java.util.List;public class App { public static void main ( String[] args ) { String resource = "mybatis-config.xml" ; InputStream inputStream = null ; try { inputStream = Resources.getResourceAsStream(resource); } catch (IOException e) { e.printStackTrace(); } SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); List<User> users = sqlSession.selectList("test.selectAll" ); System.out.println(users); sqlSession.close(); } }
解决sql报错
产生原因:idea和数据库没有建立链接,不识别表信息
解决方法:在idea中配置mysql数据库链接
Mapper代理开发 1 2 3 4 5 6 7 8 9 SqlSession sqlSession = sqlSessionFactory.openSession();List<User> users = sqlSession.selectList("test.selectAll" ); 更换写法 UserMapper userMapper = sqlSession.getMapper(UserMapper.class);List<User> users = userMapper.selectAll();
Mapper代理步骤
定义与SQL映射文件同名的Mapper接口,并将Mapper接口和SQL映射文件放置在同一目录 下
设置SQL映射文件的namespace属性为Mapper接口全限定名
在Mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 第一步 在resource文件夹下建立新的文件夹,与mapper文件夹格式一样,再把UserMapper拖入该包中 注意如果不是软件包需要'/'来分格,而不是'.' 例如:新建文件夹名:"org.exmple.mapper" 第二步 namespace值改为接口全限定名 例如: <mapper namespace="org.example.mapper.UserMapper"> <select id="selectAll" resultType="org.example.pojo.User"> select * from bookta; </select> </mapper> 第三步 在接口中定义方法 public interface UserMapper { User selectAll(); } 如果返回是个集合则要改为List: public interface UserMapper { List<User> selectAll(); } 第四步 更改配置文件中映射路径 <mappers> <mapper resource="org/example/mapper/UserMapper.xml"/> </mappers>
tip:如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载:
1 2 3 <mappers > <package name ="org.example.mapper" /> </mappers >
其他配置名 typeAliases -> 别名
在配置文件中直接添加typeAlisaes可以直接扫包,这样在UserMapper返回类型中可以直接使用类型名字
扫包是最简单的方法
1 2 3 4 5 6 7 8 9 10 11 mybatis-config: <typeAliases > <package name ="com.itheima.mapper" /> </typeAliases > UserMapper: <mapper namespace ="org.example.mapper.UserMapper" > <select id ="selectAll" resultType ="User" > select * from bookta; </select > </mapper >
注意:书写时需要遵循先后顺序!
增删改查 配置文件完成增删改查 查找 数据库表的字段名称和实体类的属性名称不一样,则不能自动封装数据
方法一:
起别名:对不一样的列名起别名,让别名和实体类的属性名一样(不建议)
可以引入sql片段解决
1 2 3 4 5 <sql id ="test" > ... </sql > select <include refid ="test" />
方法二:
resultMap 解决
1 2 3 4 5 6 7 8 9 <resultMap id ="名字(标识)" type ="类型名" > 里面有id和result两个属性,其中id用来对主键进行映射,result进行对一般字段的映射 <result column ="列名称(数据库中)" property ="属性名(自己pojo类中)" /> </resultMap > 把resultType替换成resultMap <select id ="selectAll" resultMap ="上面的id名称" > select * from bookta; </select >
占位符 #{key}或者 ${key}
#{}会替换为?,防止sql注入
${}会拼sql,会存在sql注入问题
表名或者列名不固定的时候可以使用${}
1 2 3 4 <select id ="selectAll" resultType ="返回类型" > select * from bookta where id = #{id}; </select > parameterType不是很重要,会自动按类型装配
1 2 接口 (类型) selectById(int id);
特殊字符处理
转义字符:小于号(<) -> <
多用于特殊字符少的时候
CDATA区 -> 输入CD回车 -> 出现CDATA区,在内部写入即可 多用于特殊字符多的时候
多条件查询 模糊匹配 SQL参数 like %需要查询数据 %
散装参数:@Param(“SQL占位符名称”)
1 @Param("SQL占位符名称") 类型 变量名
如果有对象可以直接传对象
传递map,需要key对应
动态条件查询 SQL语句会随着用户的输入或外部条件的变化而变化,我们称为动态SQL
mybatis提供许多标签:if 等
if & where 1 2 3 4 <if test ="逻辑表达式" > SQL语句 </if > 这里面字符串的不等于不能用equals方法,应该用!=,&&应换成and
该语句可能会出现问题,比如sql语句最终多个and
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 第一条不成立时会出错 where <if test ="逻辑表达式" > SQL语句 </if > <if test ="逻辑表达式" > and SQL语句 </if > <if test ="逻辑表达式" > and SQL语句 </if > 解决方法一: where 1 = 1 <if test ="逻辑表达式" > and SQL语句 </if > <if test ="逻辑表达式" > and SQL语句 </if > <if test ="逻辑表达式" > and SQL语句 </if > 解决方法二:使用where标签来替换where关键字 <where > <if test ="逻辑表达式" > and SQL语句 </if > <if test ="逻辑表达式" > and SQL语句 </if > <if test ="逻辑表达式" > and SQL语句 </if > </where >
choose(when, otherwise) 类似于switch
1 2 3 4 5 6 7 8 9 10 11 12 13 <choose > <when test ="逻辑表达式" > SQL语句 </when > <when test ="逻辑表达式" > SQL语句 </when > <otherwise > SQL语句 </otherwise > </choose > 可以使用where标签进行优化,如果没有条件的话where标签不会生成where
添加 事务默认为关闭,所以会导致添加不上去,需要手动提交事务
1 2 3 执行完命令之后使用 sqlSession.commit(); 进行手动提交事务
可以在获取SqlSeiion对象的时候设置自动提交事务
1 2 SqlSession sqlSession = sqlSessionFactory.openSession(true );如果为false 则需要手动提交事务
添加,主键返回 设置属性keyProperty=”主键名”即可拿出id的值,同时需要设置userGeneratedKeys=’true’
1 2 3 4 <insert id ="insertTest" useGeneratedKeys ="true" keyProperty ="id" > insert into table_name (name) VALUES (#{name}); </insert >
修改 修改全部字段 1 2 3 4 5 <update id ="updateTest" > update table_name set name = #{name} where id = #{id}; </update >
修改动态字段 使用<set>
用法和<where>
一样
1 2 3 4 5 6 7 public interface TestMapper { 返回值类型可以为int ,如果为int 则返回的是修改的行数 int updateTest (Test test) ; 不返回行数 void updateTest (Test test) ; }
删除 1 2 3 4 5 <delete id ="deleteTest" > delete from table_name where id = #{id}; </delete >
批量删除 编写接口方法
1 void deleteByIds (@Param('ids') int [] ids) ;
编写sql语句
collection :遍历的数组名
item :属性
separator :分隔符号
open和close :开头和结尾
1 2 3 4 5 6 7 8 <delete id ="deleteTests" > delete from table_name where id in <foreach collection ="ids" item ="id" separator ="," open ="(" close =")" > #{id} </foreach > </delete >
如果不用@Param,那么底下的collection的值改为”array”
其他 MyBatis中多个参数时会封装为Map集合
1 2 void deleteByIds(@Param('user') String user1); -> Map['user'] = user1
注解完成增删改查 一般用户简单功能
查询:**@Select(sql语句)**
添加:**@Insert(sql语句)**
修改:**@Update(sql语句)**
删除:**@Delete(sql语句)**
MyBatis-plus 配置文件 1 2 3 4 5 6 7 8 9 10 <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus-boot-starter</artifactId > <version > 3.2.0</version > </dependency > <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus</artifactId > <version > 3.2.0</version > </dependency >
使用 需要继承BaseMapper
1 2 3 @Mapper public interface UserDao extends BaseMapper <User>{}
打印sql 需要在配置文件中加上
1 mybatis-plus.configuration.log-impl =org.apache.ibatis.logging.stdout.StdOutImpl
复杂Sql 对查询用QueryWrapper
,对修改用UpdateWrapper
需要先构造一个QueryWrapper<pojo>
,再对其规则进行规定,例如:
1 2 3 4 5 void selectStaff () { QueryWrapper<Staff> qw = new QueryWrapper <>(); qw.likeRight("tel" ,"6" ); System.out.println(staffService.list(qw)); }
注意 :不支持以及不赞成在 RPC 调用(远程过程调用)中把 Wrapper 进行传输(以下为官方解释)
wrapper 很重
传输 wrapper 可以类比为你的 controller 用 map 接收值(开发一时爽,维护火葬场)
正确的 RPC 调用姿势是写一个 DTO 进行传输,被调用方再根据 DTO 执行相应的操作
我们拒绝接受任何关于 RPC 传输 Wrapper 报错相关的 issue 甚至 pr
主键自动填充 id要想自动填充,需要在pojo类中添加注解@TableId
1 2 3 4 5 6 7 8 9 10 @Data public class Staff { private String name; private String tel; private String account; private String password; private Boolean manager; @TableId(value = "id", type = IdType.ID_WORKER) private Long id; }
其中type有多种选择
这里注意如果id是整型,那么数据库中id应为bigint java中id为Long 类型 因为自动生成是自动生成19位,会超出int范围
代码生成器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 package com.manpower.generator; import com.baomidou.mybatisplus.generator.FastAutoGenerator; import com.baomidou.mybatisplus.generator.config.OutputFile; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; import java.sql.SQLException; import java.util.Collections; public class CodeGenerator { public static void main (String[] args) throws SQLException { String username = "root" ; String password = "csh20011103" ; FastAutoGenerator.create(url, username, password) .globalConfig(builder -> { builder .author("haog" ) .fileOverride() }) .packageConfig(builder -> { .moduleName("" ) .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "F:\\editor\\project\\manpower\\src\\main\\resources\\mapper" )); }) .templateEngine(new FreemarkerTemplateEngine ()) .strategyConfig(builder -> { .entityBuilder() .enableLombok() .enableTableFieldAnnotation() .naming(NamingStrategy.underline_to_camel) .columnNaming(NamingStrategy.underline_to_camel) .controllerBuilder() .enableRestStyle() .serviceBuilder() .mapperBuilder() .enableBaseResultMap(); }) .execute(); } }
所需要的jar包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-freemarker</artifactId > <version > 2.4.4</version > </dependency > <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus-boot-starter</artifactId > <version > 3.4.0</version > </dependency > <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus</artifactId > <version > 3.4.0</version > </dependency > <dependency > <groupId > org.apache.velocity</groupId > <artifactId > velocity-engine-core</artifactId > <version > 2.2</version > </dependency > <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus-generator</artifactId > <version > 3.5.1</version > </dependency >
注意!需要在mapper 中手动加上**@Mapper**,实体类中要加上toString 方法,否则会返回值会为地址 官方service使用文档:CRUD 接口 | MyBatis-Plus (baomidou.com)