兴趣爱好 Java java学习笔记 -MyBatis 执笔 2023-05-15 2024-06-10 MyBatis搭建
引入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <dependencies > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.7</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > <scope > test</scope > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 5.1.3</version > </dependency > </dependencies >
MyBatis的核心配置文件
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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <properties resource ="jdbc.properties" /> <settings > <setting name ="mapUnderscoreToCamelCase" value ="true" /> <setting name ="lazyLoadingEnabled" value ="true" /> </settings > <typeAliases > <package name ="com.zhibi.mybatis.pojo" /> </typeAliases > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="${jdbc.driver}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> </dataSource > </environment > </environments > <mappers > <package name ="com.zhibi.mybatis.mapper" /> </mappers > </configuration >
创建Mapper接口
1 2 3 4 5 6 7 8 9 public interface UserMapper { }
创建映射文件
Java概念
数据库概念
类
表
属性
字段/列
对象
记录/行
表所对应的实体类的类名+Mapper.xml
存放的位置是src/main/resources/mappers
目录下
1 2 3 4 5 6 7 8 9 10 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.zhibi.mybatis.mapper.UserMapper" > <insert id ="insertUser" > insert into t_user values(null,'admin','123',18,'男','123@qq.com') </insert > </mapper >
通过junit测试功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class UserMapperTest { @Test public void testInsertUser () throws IOException { InputStream is = Resources.getResourceAsStream("mybatis-config.xml" ); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder (); SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true ); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); int result = userMapper.insertUser(); System.out.println("result:" + result); } }
此时需要手动提交事务,如果要自动提交事务,则在获取sqlSession对象时,使用SqlSession sqlSession = sqlSessionFactory.openSession(true);
,传入一个Boolean类型的参数,值为true,这样就可以自动提交
加入log4j功能
引入依赖
1 2 3 4 5 6 <dependency > <groupId > log4j</groupId > <artifactId > log4j</artifactId > <version > 1.2.17</version > </dependency >
加入配置文件
log4j的配置文件名为log4j.xml,存放的位置是src/main/resources目录下
日志的级别:FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试) 从左到右打印的内容越来越详细
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 log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender"> <param name="Encoding" value="UTF-8" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" /> </layout> </appender> <logger name="java.sql"> <level value="debug" /> </logger> <logger name="org.apache.ibatis"> <level value="info" /> </logger> <root> <level value="debug" /> <appender-ref ref="STDOUT" /> </root> </log4j:configuration>
默认的类型别名


增删改查
添加
1 2 3 4 <insert id ="insertUser" > insert into t_user values(null,'admin','123456',23,'男','12345@qq.com') </insert >
删除
1 2 3 4 <delete id ="deleteUser" > delete from t_user where id = 6 </delete >
修改
1 2 3 4 <update id ="updateUser" > update t_user set username = '张三' where id = 5 </update >
查询一个实体类对象
1 2 3 4 <select id ="getUserById" resultType ="com.atguigu.mybatis.bean.User" > select * from t_user where id = 2 </select >
查询集合
1 2 3 4 <select id ="getUserList" resultType ="com.atguigu.mybatis.bean.User" > select * from t_user </select >
1 2 3 查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射关系 - resultType:自动映射,用于属性名和表中字段名一致的情况 - resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况
获取参数值方式
MyBatis获取参数值的两种方式:${}和#{}
${}的本质就是字符串拼接,#{}的本质就是占位符赋值
${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号
单个字面量类型的参数
1 2 3 4 <select id ="getUserByUsername" resultType ="User" > select * from t_user where username = #{username} </select >
1 2 3 4 <select id ="getUserByUsername" resultType ="User" > select * from t_user where username = '${username}' </select >
多个字面量类型的参数
以param1,param2…为键,以参数为值;
1 2 3 4 5 <select id ="login" resultType ="User" > select * from t_user where username = '${param1}' and password = '${param2}' </select >
map集合类型的参数
1 2 3 4 <select id ="checkLogin" resultType ="User" > select * from t_user where username = #{username} and password = #{password} </select >
1 2 3 4 5 6 7 8 9 public void testCheckLogin () { SqlSession sqlSession = SqlSessionUtils.getSqlSession(); ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class); HashMap<String, Object> map = new HashMap <>(); map.put("username" ,"admin" ); map.put("password" ,"123" ); User user = mapper.checkLogin(map); System.out.println(user); }
实体类类型的参数
1 2 3 4 <insert id ="insertUser" > insert into t_user values(null,#{username},#{password},#{age},#{sex},#{email}) </insert >
使用@Param标识参数(主要使用)
1 2 3 4 <select id ="loginByParam" resultType ="User" > select * from t_user where username = #{username} and password = #{password} </select >
查询功能
查询一个实体类
1 2 3 4 5 6 User getUserById (@Param("id") int id) ;
1 2 3 4 <select id ="getUserById" resultType ="User" > select * from t_user where id = #{id} </select >
查询一个List集合
1 2 List<User> getUserList () ;
1 2 3 4 <select id ="getUserList" resultType ="User" > select * from t_user </select >
查询单个数据
1 2 3 4 5 6 7 8 9 int getCount () ;
1 2 3 4 <select id ="getCount" resultType ="_integer" > select count(id) from t_user </select >
查询一条数据为map集合
1 2 3 4 5 6 Map<String, Object> getUserToMap (@Param("id") int id) ;
1 2 3 4 5 <select id ="getUserToMap" resultType ="map" > select * from t_user where id = #{id} </select >
查询多条数据为map集合
方法一
1 2 3 4 5 6 List<Map<String, Object>> getAllUserToMap () ;
1 2 3 4 5 6 7 8 9 10 <select id ="getAllUserToMap" resultType ="map" > select * from t_user </select >
方法二
1 2 3 4 5 6 7 @MapKey("id") Map<String, Object> getAllUserToMap () ;
1 2 3 4 5 6 7 8 9 10 11 12 <select id ="getAllUserToMap" resultType ="map" > select * from t_user </select >
特殊SQL的执行
模糊查询
1 2 3 4 5 6 7 <select id ="getUserByLike" resultType ="User" > select * from t_user where username like "%"#{username}"%" </select >
批量删除
只能使用${},如果使用#{},则解析后的sql语句为delete from t_user where id in ('1,2,3')
,这样是将1,2,3
看做是一个整体,只有id为1,2,3
的数据会被删除。正确的语句应该是delete from t_user where id in (1,2,3)
,或者delete from t_user where id in ('1','2','3')
1 2 3 4 5 <delete id ="deleteMore" > delete from t_user where id in (${ids}) </delete >
动态设置表名
1 2 3 4 <select id ="getUserByTable" resultType ="User" > select * from ${tableName} </select >
添加功能获取自增的主键
1 2 3 4 5 6 7 8 <insert id ="insertUser" useGeneratedKeys ="true" keyProperty ="id" > insert into t_user values(null,#{username},#{password},#{age},#{sex},#{email}) </insert >
1 2 3 4 5 6 7 8 9 10 @Test public void testInsertUser () { SqlSession sqlSession = SqlSessionUtils.getSqlSession(); SQLMapper mapper = sqlSession.getMapper(SQLMapper.class); User user = new User (null ,"关羽" ,"123" ,18 ,"男" ,"guanyu@qq.com" ); mapper.insertUser(user); System.out.println(user); }
自定义映射
若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射,即使字段名和属性名一致的属性也要映射,也就是全部属性都要列出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <select id ="getAllEmp" resultMap ="empResultMapper" > select * from t_emp </select > <resultMap id ="empResultMapper" type ="Emp" > <id property ="eid" column ="eid" > </id > <result property ="empName" column ="emp_name" > </result > <result property ="age" column ="age" > </result > <result property ="sex" column ="sex" > </result > <result property ="email" column ="email" > </result > </resultMap >
若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性名符合Java的规则(使用驼峰)。此时也可通过以下两种方式处理字段名和实体类中的属性的映射关系
1 2 3 4 5 6 1. 可以通过为字段起别名的方式,保证和实体类中的属性名保持一致 ```xml <!--List<Emp> getAllEmp();--> <select id="getAllEmp" resultType="Emp"> select eid,emp_name empName,age,sex,email from t_emp </select>
可以在MyBatis的核心配置文件中的setting
标签中,设置一个全局配置信息mapUnderscoreToCamelCase,可以在查询表中数据时,自动将_类型的字段名转换为驼峰,例如:字段名user_name,设置了mapUnderscoreToCamelCase,此时字段名就会转换为userName。核心配置文件详解 1 2 3 <settings > <setting name ="mapUnderscoreToCamelCase" value ="true" /> </settings >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ## 多对一映射 ### 级联属性赋值 ```xml <!--处理多对一映射关系方式一:级联属性赋值--> <resultMap id="empAndDeptResultMaoOne" type="Emp"> <id property="eid" column="eid"></id> <result property="empName" column="emp_name"></result> <result property="age" column="age"></result> <result property="sex" column="sex"></result> <result property="email" column="email"></result> <result property="dept.did" column="did"></result> <result property="dept.deptName" column="dept_name"></result> </resultMap>
assication标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <resultMap id ="empAndDeptResultMapTwo" type ="Emp" > <id property ="eid" column ="eid" > </id > <result property ="empName" column ="emp_name" > </result > <result property ="age" column ="age" > </result > <result property ="sex" column ="sex" > </result > <result property ="email" column ="email" > </result > <association property ="dept" javaType ="Dept" > <id property ="did" column ="did" > </id > <result property ="deptName" column ="dept_name" > </result > </association > </resultMap > <select id ="getEmpAndDept" resultMap ="empAndDeptResultMapTwo" > select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid} </select >
分步查询
查询员工信息
1 2 3 4 5 Emp getEmpAndDeptByStepOne (@Param("eid") Integer eid) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <select id ="getEmpAndDeptByStepOne" resultMap ="empAndDeptBySeptResultMap" > select * from t_emp where eid = #{eid} </select > <resultMap id ="empAndDeptBySeptResultMap" type ="Emp" > <id property ="eid" column ="eid" > </id > <result property ="empName" column ="emp_name" > </result > <result property ="age" column ="age" > </result > <result property ="sex" column ="sex" > </result > <result property ="email" column ="email" > </result > <association property ="dept" select ="com.zhibi.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo" column ="did" fetchType ="eager" > </association > </resultMap >
查询部门信息
1 2 3 4 5 Dept getEmpAndDeptByStepTwo (@Param("did") Integer did) ;
1 2 3 4 5 6 7 8 9 10 <select id ="getEmpAndDeptByStepTwo" resultMap ="EmpAndDeptByStepTwo" > select * from t_dept where did = #{did} </select > <resultMap id ="EmpAndDeptByStepTwo" type ="Dept" > <id property ="did" column ="did" > </id > <result property ="deptName" column ="dept_name" > </result > </resultMap >
一对多映射
connection标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <resultMap id ="DeptAndEmpResultMap" type ="Dept" > <id property ="did" column ="did" > </id > <result property ="deptName" column ="dept_name" > </result > <collection property ="emps" ofType ="Emp" > <id property ="eid" column ="eid" > </id > <result property ="empName" column ="emp_name" > </result > <result property ="age" column ="age" > </result > <result property ="sex" column ="sex" > </result > <result property ="email" column ="email" > </result > </collection > </resultMap > <select id ="getDeptAndEmp" resultMap ="DeptAndEmpResultMap" > select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did} </select >
分步查询
查询部门信息
1 2 3 4 5 Dept getDeptAndEmpByStepOne (@Param("did") Integer did) ;
1 2 3 4 5 6 7 8 9 10 11 <resultMap id ="DeptAndEmpByStepResultMap" type ="Dept" > <id property ="did" column ="did" > </id > <result property ="deptName" column ="dept_name" > </result > <collection property ="emps" select ="com.zhibi.mybatis.mapper.EmpMapper.getDeptAndEmpBySeptTwo" column ="did" > </collection > </resultMap > <select id ="getDeptAndEmpByStepOne" resultMap ="DeptAndEmpByStepResultMap" > select * from t_dept where did = #{did} </select >
查询员工信息
1 2 3 4 5 List<Emp> getDeptAndEmpBySeptTwo (@Param("did") Integer did) ;
1 2 3 4 <select id ="getDeptAndEmpBySeptTwo" resultType ="Emp" > select * from t_emp where did = #{did} </select >
延迟加载
1 2 3 4 5 6 7 <settings > <setting name ="mapUnderscoreToCamelCase" value ="true" /> <setting name ="lazyLoadingEnabled" value ="true" /> </settings >
开启后,需要用到查询dept的时候才会调用相应的SQL语句
1 2 3 4 5 6 7 @Test public void getEmpAndDeptByStepOne () { SqlSession sqlSession = SqlSessionUtils.getSqlSession(); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); Emp emp = mapper.getEmpAndDeptByStepOne(1 ); System.out.println(emp.getEmpName()); }


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <resultMap id ="empAndDeptBySeptResultMap" type ="Emp" > <id property ="eid" column ="eid" > </id > <result property ="empName" column ="emp_name" > </result > <result property ="age" column ="age" > </result > <result property ="sex" column ="sex" > </result > <result property ="email" column ="email" > </result > <association property ="dept" select ="com.zhibi.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo" column ="did" fetchType ="eager" > </association > </resultMap >
动态SQL
if
根据标签中test属性所对应的表达式决定是否需要将内容拼接到SQL中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <select id ="getEmpByConditionOne" resultType ="Emp" > select * from t_emp <where > <if test ="empName != null and empName != ''" > and emp_name = #{empName} </if > <if test ="age != null and age != ''" > and age = #{age} </if > <if test ="sex != null and sex != ''" > and sex = #{sex} </if > </where > </select >
where
当where标签中有内容时,会自动生成where关键字,并且将内容前的and或者or去除
当where标签中没有内容时,where标签不生效
注意:where标签不能将内容后的and或者or去除
trim
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <select id ="getEmpByCondition" resultType ="Emp" > select <include refid ="empColumns" > </include > from t_emp <trim prefix ="where" suffix ="" prefixOverrides ="" suffixOverrides ="and|or" > <if test ="empName != null and empName != ''" > emp_name = #{empName} and </if > <if test ="age != null and age != ''" > and age = #{age} or </if > <if test ="sex != null and sex != ''" > sex = #{sex} </if > </trim > </select >
choose、when、otherwise
类似于switch … case … default
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <select id ="getEmpByChoose" resultType ="Emp" > select * from t_emp <where > <choose > <when test ="empName != null and empName != ''" > emp_name = #{empName} </when > <when test ="age != null and age != ''" > age = #{age} </when > <when test ="sex != null and sex != ''" > sex = #{sex} </when > <when test ="email != null and email != ''" > email = #{email} </when > <otherwise > age = 1 </otherwise > </choose > </where > </select >
foreach
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 <delete id ="deleteEmpByArray" > delete from t_emp where <foreach collection ="eids" item ="eid" separator ="or" > eid = #{eid} </foreach > </delete > <insert id ="insertMore" > insert into t_emp values <foreach collection ="emps" separator ="," item ="emp" > (null,#{emp.empName},#{emp.age},#{emp.sex},#{emp.email},null) </foreach > </insert >
SQL片段
sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引入
声明sql片段:<sql>
标签
1 <sql id ="empColumns" > eid,emp_name,age,sex,email</sql >
1 2 3 4 <select id ="getEmpByCondition" resultType ="Emp" > select <include refid ="empColumns" > </include > from t_emp </select >
MyBatis缓存查询的顺序
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存