MyBatis
MyBatis是一款优秀的持久层框架,用于简化JDBC开发
持久层
负责将数据保存到数据库的那一层代码
JavaEE三层架构:表现层、业务层、持久层。
框架
框架就是一个半成品,是一套可重用的、通用的、软件基础代码模型
在框架的基础上构建软件是的软件编写更加高效、规范、通用、可扩展
MyBatis简化
硬编码
注册驱动
获取连接
操作繁琐
手动设置参数
手动封装结果集
入门代码框架 项目结构
主要文件代码 User.java 数据类,查出来的数据将以User的实例形式保存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.littleblack.demo;import lombok.Data;@Data public class User { private Integer id; private String username; private String password; }
MyBatisDemo.java 核心控制类
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 package com.littleblack;import com.littleblack.demo.User;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 java.io.IOException;import java.io.InputStream;import java.util.List;public class MyBatisDemo { 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(); } }
编写时如果出现红色报错,可使用Alt + Enter快捷键导入类
mybatis-config.xml 核心配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?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:///db1?useSSL=false" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="userMapper.xml" /> </mappers > </configuration >
主要修改driver、url、username、password
UserMapper.xml 映射类
用于配置具体的sql语句,命名方式一般为查询表名 + Mapper
1 2 3 4 5 6 7 8 9 <?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 ="test" > <select id ="selectAll" resultType ="com.littleblack.demo.User" > select * from db1.tb_user; </select > </mapper >
pom.xml
由于本人配置时出现了因为版本不合和缺少导入包等各种阿巴阿巴的问题,所以贴出maven配置,供大家参考
——2022/3/10
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 <?xml version="1.0" encoding="UTF-8"?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > org.example</groupId > <artifactId > myBatis--demo</artifactId > <version > 1.0-SNAPSHOT</version > <dependencies > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.9</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.28</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.13.2</version > <scope > test</scope > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-api</artifactId > <version > 1.7.25</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-nop</artifactId > <version > 1.7.2</version > </dependency > <dependency > <groupId > ch.qos.logback</groupId > <artifactId > logback-core</artifactId > <version > 1.2.10</version > </dependency > <dependency > <groupId > ch.qos.logback</groupId > <artifactId > logback-core</artifactId > <version > 1.2.10</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.22</version > <scope > compile</scope > </dependency > </dependencies > <properties > <maven.compiler.source > 16</maven.compiler.source > <maven.compiler.target > 16</maven.compiler.target > </properties > </project >
Mapper代理开发 目的
1 2 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List< User > users = userMapper.selectAll();
不依赖字符串全面值,且可以借助IDE的自动补全功能
使用
定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下。(创建时可使用com/littleblack/demo来代替com/littleblack.demo)
设置SQL映射文件的namespace属性为Mapper接口全限定名。
在Mapper接口中定义方编码法,方法名就是SQL映射文件中SQL语句的id,并保持参数类型和返回值类型一致。
编码:
通过SqlSession的getMapper方法获取Mapper接口的代理对象。
调用对应方法完成sql的执行。
注:如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载
mybatis-config.xml文件中内容如下
1 2 3 4 5 6 7 <mappers > <mapper resource ="com/littleblack/mapper/UserMapper.xml" /> <package name ="com.littleblack.mapper" /> </mappers >
两种方法等效,推荐使用第二种方法
源码展示 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 package com.littleblack;import com.littleblack.demo.User;import com.littleblack.mapper.UserMapper;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.contract4j5.contract.Post;import org.contract4j5.contract.Pre;import java.io.IOException;import java.io.InputStream;import java.util.List;public class MyBatisDemo2 { public static void main (String[] args) throws IOException { 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(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> users = userMapper.selectAll(); System.out.println(users); sqlSession.close(); } }
MyBatis核心配置文件 environments标签 1 <environments default ="development" >
配置数据库连接环境信息,其中可包含多个数据库,可以配置多个environment,通过default属性切换不同的environment
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <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:///db1" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > <environment id ="test" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.cj.jdbc.Driver" /> <property name ="url" value ="jdbc:mysql:///student" /> <property name ="username" value ="root" /> <property name ="password" value ="root" /> </dataSource > </environment > </environments >
transactionManager 事物关系信息,暂时不用考虑
dataSource 数据库连接池,暂时不用考虑
typeAliases 别名
1 2 3 4 <configuration > <typeAliases > <package name ="com.littleblack.demo" /> </typeAliases >
在mapper中resultType中就可以直接使用类名称而不需要添加包名
1 2 3 4 5 <mapper namespace ="com.littleblack.mapper.UserMapper" > <select id ="selectAll" resultType ="User" > select * from db1.tb_user; </select > </mapper >
同时,如果出现封装类中变量名称和数据库中属性名称不一样的情况会导致返回数据无法自动封装,这个时候也可以使用别名
1 2 3 <select id ="selectAll" resultType ="User" > select id, username as userName, password as passWord from db1.tb_user; </select >
如果觉得每次都需要重新定义别名很麻烦,可使用sql片段
1 2 3 4 5 6 7 8 <sql id ="brand_column" > id, username, password </sql > <select id ="selectAll" resultType ="User" > select <include refid ="brand_column" /> from db1.tb_user; </select >
但是这种方法不推荐,片段化的sql语句可能会引起IDE报错并且无法使用自动补全
撰写映射 推荐方法:撰写映射
定义resultMap标签
在select标签中,使用resultMap属性替换resultType属性
1 2 3 4 5 6 7 8 <resultMap id ="UserMapper" type ="User" > <result column ="id" property ="id" /> <result column ="username" property ="username" /> <result column ="password" property ="password" /> </resultMap > <select id ="selectAll" resultMap ="UserMapper" > select * from db1.tb_user; </select >
映射中可以只写数据库属性名称和映射类名称不一样的,一样的可以不用写
1 2 <id column ="id" property ="id" /> <result column ="username" property ="username" />
id用于完成主键字段的映射
result用于完成其他字段的映射
最好还是直接映射类中的变量和数据库中的一一对应
参数占位符
#{}:执行SQL时,会将#{}占位符替换为?,将来自动设置参数值
${}:通过SQL语句拼接的方式执行,存在SQL注入的风险
参数传递可以直接使用#{}
但是如果需要对表名或者列名动态设置,则只能使用${}进行sql拼接
parameterType
SQL语句中特殊字符处理 转义字符
转义表示
符号
符号含义
& amp; 或 &
&
和
& lt; 或 <
<
小于号
& gt; 或 >
>
大于号
& quot;
“
双引号
& nbsp;
空格
& copy;
©
版权符
& reg;
®
注册符
代码区
查询 传递参数的方式:
1 2 3 void insert (@Param("id") int id, @Param("username") String username, @Param("password") String password) ;void insert (User user) ;void insert (Map map) ;
1 2 3 <insert id ="insert" > insert db1.tb_user values (#{id}, #{username}, #{password}); </insert >
如果使用参数传递,可以使用@Param标注参数对应的位置
如果使用类传递,则需要保证映射类的变量名称和xml中的变量名称一致
如果使用map传递,则需要保证map中key的名称和xml中的变量名称一致
多条件动态查询 1 User selectByCondition (User user) ;
传递参数方式同上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <select id ="selectByCondition" resultMap ="UserMapper" > select * from tb_user <where > <if test ="id != null" > id = #{id} </if > <if test ="username != null and username != ''" > and username like #{username} </if > <if test ="password != null and password != ''" > and password like #{password} </if > </where > </select >
使用if标签判断哪些参数需要使用,哪些不需要
但是如果第一个参数不需要的话,sql语句将会变成”select * from tb_user where and username like #{username}”,这会造成语法检查无法通过,所以使用一个where标签,会自动判断是否加上and
单条件动态查询 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <select id ="selectByCondition" resultMap ="UserMapper" > select * from tb_user <where > <choose > <when test ="id != null" > id = #{id} </when > <when test ="username != null and username != ''" > and username like #{username} </when > <when test ="password != null and password != ''" > and password like #{password} </when > <otherwise /> </choose > </where > </select >
choose类似Switch
when类似case(带break,只能执行一次)
otherwise类似default
添加 1 2 3 void insert (User user) ;void insert (@Param("id") int id, @Param("username") String username, @Param("password") String password) ;void insert (Map map) ;
1 2 3 <insert id ="insert" > insert db1.tb_user values (#{id}, #{username}, #{password}); </insert >
如何在添加完后获取添加行主键的值呢?
1 2 3 <insert id ="insert" useGeneratedKeys ="true" keyProperty ="id" > insert db1.tb_user values (#{id}, #{username}, #{password}); </insert >
使用useGenerateedKeys和keyProperty标签映射至数据库内设置好的自动增加的主键列中,执行完后该对象或者该变量的值会被自动写入,只需要再次读取就可以获取到添加行主键的值。
修改 1 2 3 4 void update (@Param("id") int id, @Param("password") String password) ;void update (User user) ;void update (Map map) ;
1 2 3 <update id ="update" > update db1.tb_user set password = #{password} where id = #{id}; </update >
删除 单个删除 1 void deleteByID (int id) ;
1 2 3 <delete id ="deleteByID" > delete from tb_user where id = #{id}; </delete >
批量删除 1 2 3 4 5 6 @Test public void testDeleteByIDs () throws IOException { int [] id = {1 ,2 ,3 }; userMapper.deleteByID(1 ); System.out.println(userMapper.selectAll()); }
1 2 3 4 5 6 7 8 <delete id ="deleteByIds" > delete from tb_user where id in ( <foreach collection ="ids" item ="id" separator ="," > #{id}; </foreach > ); </delete >
使用foreach标签
collection表示列表名称
item表示列表内对应赋值到的变量
separator表示用来拼接的分隔符(思路还是拼成sql语句,中间没有逗号会报错)
MyBatis参数封装