MyBatis笔记：各种查询方式|特殊SQL|自定义映射|多表联查|动态SQL|逆向工程
MyBatis笔记：各种查询功能,特殊SQL语句，动态SQL语句，MyBatis中的一二级缓存，清新版和奢华版的逆向工程的使用，包括我自己的对于多表联查的视频解释，分页查询的插件，还有我对于报错的问题解决思路。篇幅较长，可以选择所需查看。各种查询方式查询单条信息/多条信息SelectMapper接口public interface SelectMapper { /* 根据id来查询用户信息/返回值可以使用User或者是List<User> */ public abstract List<User> getUserById(@Param("id") Integer id); /* 查询所有的用户信息 */ public abstract List<User> getAllUser(); }SelectMapper.xml select * from t_user where id = #{id} <!--List<User> getAllUser();--> select * from t_user 测试类public class SelectMapperTest { /** * MyBatis的各种查询功能 * 1.若查询出的数据只有一条， * a>可以通过实体类对象 * b>可以通过List集合接收 * c>可以通过Map集合接收 * * 2.若查询出的数据有多条， * a>可以通过List集合接收 * b>可以通过Map集合接收 *注意：一定不能通过实体类对象来接收，此时会抛异常TooManyResultsException * */ @Test public void testGetAllUser(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); SelectMapper mapper = sqlSession.getMapper(SelectMapper.class); //查询所有的用户信息 System.out.println("user = " + mapper.getAllUser()); } @Test public void testGetUserById(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); SelectMapper mapper = sqlSession.getMapper(SelectMapper.class); //查询用户id为3的用户信息 System.out.println("user = " + mapper.getUserById(3)); } }使用聚合函数查询单行信息SelectMapper接口 /* 查询用户信息的总记录数 */ public abstract Integer getCount();SelectMapper.xml select count(*) from t_user 查询用户信息为Map集合我们可以把查询出来的结果转换为一个map集合，以字段为键，字段对应的值为值。查询单条数据为Map集合SelectMapper接口 /* 根据id查询用户信息为一个map集合 */ public abstract Map<String, Object> getUserByIdToMap(@Param("id") Integer id);SelectMapper.xml <!--Map<String, Object> getUserByIdToMap(@Param("id") Integer id);--> select * from t_user where id = #{id} 查询多条数据为Map集合把map集合放入List集合中需要调整返回值，把多条数据的返回值放到一个List集合中，每一条转换的map放到了List集合中在接口方法上添加@MapKey注解 [label color="red"]@MapKey设置当前map集合的键，会把我们查询出来数据的某一个字段作为键(唯一)，查询出来数据的map集合作为值[/label]SelectMapper接口 /* 查询所有用户信息为map集合 */ //public abstract List<Map<String, Object>> getAllUserToMap(); @MapKey("id") public abstract Map<String, Object> getAllUserToMap();SelectMapper.xml <!--Map<String, Object> getAllUserToMap();--> select * from t_user 测试类最终源码SelectMapperTestpublic class SelectMapperTest { /** * MyBatis的各种查询功能 * 1.若查询出的数据只有一条， * a>可以通过实体类对象 * b>可以通过List集合接收 * c>可以通过Map集合接收 *结果：Map = {password=123456, sex=男, id=3, age=23, email=12345@qq.com, username=admin} * * 2.若查询出的数据有多条， * a>可以通过实体类类型的List集合接收 * b>可以通过map类型的Map集合接收 * c>可以在mapper接口方法上添加@MapKey注解， * 此时就可以将每条数据转换的map集合作为值，以某个字段的值作为键，放在同一个map集合中 *注意：一定不能通过实体类对象来接收，此时会抛异常TooManyResultsException * * MyBatis中设置了默认的类型别名 * Java.lang.Integer -->int,Integer * int --> _int,integer * Map --> map * String -->string * */ @Test public void testGetALLUserToMap(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); SelectMapper mapper = sqlSession.getMapper(SelectMapper.class); System.out.println("Map = " + mapper.getAllUserToMap()); } @Test public void testGetUserByIdToMap(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); SelectMapper mapper = sqlSession.getMapper(SelectMapper.class); //查询id为3的用户信息的map集合 System.out.println("Map = " + mapper.getUserByIdToMap(3)); } @Test public void testGetCount(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); SelectMapper mapper = sqlSession.getMapper(SelectMapper.class); //查询所有的用户信息 System.out.println("Count = " + mapper.getCount()); } @Test public void testGetAllUser(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); SelectMapper mapper = sqlSession.getMapper(SelectMapper.class); //查询所有的用户信息 System.out.println("user = " + mapper.getAllUser()); } @Test public void testGetUserById(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); SelectMapper mapper = sqlSession.getMapper(SelectMapper.class); //查询用户id为3的用户信息 System.out.println("user = " + mapper.getUserById(3)); } } SelectMapper接口public interface SelectMapper { /* 根据id来查询用户信息/返回值可以使用User或者是List<User> */ public abstract List<User> getUserById(@Param("id") Integer id); /* 查询所有的用户信息 */ public abstract List<User> getAllUser(); /* 查询用户信息的总记录数 */ public abstract Integer getCount(); /* 根据id查询用户信息为一个map集合 */ public abstract Map<String, Object> getUserByIdToMap(@Param("id") Integer id); /* 查询所有用户信息为map集合 */ //public abstract List<Map<String, Object>> getAllUserToMap(); @MapKey("id") public abstract Map<String, Object> getAllUserToMap(); } SelectMapper.xml<?xml version="1.0" encoding="UTF-8" ?> <mapper namespace="com.atguigu.mybatis.mapper.SelectMapper"> select * from t_user where id = #{id} <!--List<User> getAllUser();--> select * from t_user select count(*) from t_user <!--Map<String, Object> getUserByIdToMap(@Param("id") Integer id);--> select * from t_user where id = #{id} <!--Map<String, Object> getAllUserToMap();--> select * from t_user </mapper>特殊SQL的执行能用#{}绝对不使用${}，以下情况使用#{}将会出现一定问题。处理模糊查询处理模糊查询如果使用之前的方式可能会出现一些问题。这时候有两种方式解决使用${} select * from t_user where username like '%${username}%'依然使用#{}，只不过写SQL语句要用到 [label color="blue"]字符串拼接concat[/label] select * from t_user where username like concat('%',#{username},'%')依然使用#{},只不过在%两边加双引号 [label color="red"](最常用)[/label] select * from t_user where username like "%"#{username}"%"批量删除在使用批量删除的语句中， delete from t_user where id in () 括号中无法使用#{}，因为#{}会自动解析出来多一对单引号，SQL语句语法格式不对无法实现批量删除，而只能使用${}来获取参数。SQLMapper.xml <delete id="deleteMore"> delete from t_user where id in (${ids}) </delete>动态设置表名对于动态设置表名，只能是${}来获取参数 <!-- List<User> getUserByTableName(@Param("tableName") String tableName);--> select * from ${tableName} 添加功能获取自增的主键场景：如果有一个一对多的表关系，有一个班级表，有一个学生表。一个班级有多个学生，班级对应学生应该是一对多的关系，一对多和多对一都要把表设置在多的一方，我们需要把学生表中设置班级的id。我们可以为某个班级分配学生，就是为我们的学生设置班级，我们需要在中间获取当前添加班级的id，才能为班级分配学生。JDBC中本身就有这样的功能，来获取添加自增的主键，JDBC中的主键回显而mybatis中也可以实现 <insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> insert into t_user values (null,#{username},#{password},#{age},#{sex},#{email}) </insert>自定义映射resultMap之前实现查询功能，使用resultType，默认映射关系，要求字段名和属性名一致。把我们查询出来对应的字段名为属性赋值，如果当前字段名和属性名 [label color="red"]不一致[/label] ，或者是多对一、一对多的关系就需要使用resultMap。java中属性名遵循驼峰命名，MySQL中习惯以_分隔。如果字段名和属性名不一致，如果不改变命名的前提下，解决字段名和属性名不一致有三种方式。场景：有一个员工表和一个部门表，员工表中有一个部门id对应一个部门表中的部门id，产生了多对一和一对多在编写SQL语句时使用别名的形式，查询出来的字段名和属性名一致，就可以正常赋值。EmpMapper.xml <!--List<Emp> getAllEmp();--> select eid,emp_name empName,age,sex,email from t_emp 添加全局配置[font size="16" color="#240a40"]mapUnderscoreToCamelCase[/font]mybatis-config.xml<?xml version="1.0" encoding="UTF-8" ?> <configuration> <properties resource="jdbc.properties"/> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <typeAliases> <package name="com.atguigu.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.atguigu.mybatis.mapper"/> </mappers> </configuration>EmpMapper.xml <!--List<Emp> getAllEmp();--> select * from t_emp 使用resultMap设置自定义映射EmpMapper.xml <resultMap id="empResultMap" 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>使用resultMap处理有点麻烦，一般resultMap是来处理一对多和多对一的问题的。多对一的映射处理表和表直接有关系，表所映射的实体类直接也是存在一定的关系。Emp类public class Emp { private Integer eid; //使用驼峰命名 private String empName; private Integer age; private String sex; private String email; //多对一，创建一所对应的对象就可以 private Dept dept; [font size="16.5" color="#ff0000"]多对一创建一所对应的对象就可以，一对多设置一个集合就可以。[/font]处理多对一的映射关系也有三种方法使用级联属性赋值EmpMapper.xml <resultMap id="empAndDeptResultMapOne" 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> select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid} 使用association标签实现使用association标签处理多对一的关系EmpMapper.xml <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 * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid = #{eid} 使用分步查询我们可以通过多个SQL语句一步步来实现，我们可以先查员工，通过员工的部门id查询部门信息。我只提供两个xml文件的书写方式，附上视频。[video title="多对一分步查询 " url="https://img.kaijavademo.top/typecho/uploads/2023/08/videos/2023-08-22%2002-42-15.mkv " container="beyz03osczc" subtitle=" " poster=" "] [/video]EmpMapper.xml <resultMap id="empAndDeptByStepResultMap" 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.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo" column="did"></association> </resultMap> select * from t_emp where eid = #{eid} DeptMapper.xml select * from t_dept where did = #{did} 延迟加载[note type="info flat"]通过使用多表联查，将当前一个完整的过程分布进行，有什么好处？并不是很麻烦，两个SQL语句放在一起就可以实现一个功能，不放在一起，那么他们各自也可以实现对应的功能。分布查询可以开启延迟加载(懒加载)之后，当前只访问员工信息，只查询员工。如果访问员工以及员工所对应的部门，即会执行当前员工的SQL，又会执行查询部门的SQL。[/note]MyBatis默认不开启延迟加载，我们需要手动开启lazyLoadingEnabled：延迟加载的全局开关。当开启时，所有关联对象都会延迟加载aggressiveLazyLoading：当开启时，任何方法的调用都会加载该对象的所有属性。 否则，每个属性会按需加载我们需要设置lazyLoadingEnabled为 [label color="red"]true[/label] ，aggressiveLazyLoading为 [label color="default"]false[/label] 。全局配置中开启延迟加载的功能，对于所有分布查询都是会延迟加载。当前有些功能如果不需要延迟加载，就需要通过在分布查询中的一个属性[font size="15.5" color="#240a40"]fetchType[/font]延迟或立即加载，使得延迟加载可控。[font size="15.5" color="#240a40"]fetchType[/font]有两个属性eager立即加载lazy延迟加载EmpMapper.xml <resultMap id="empAndDeptByStepResultMap" 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.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo" column="did" fetchType="eager"></association> </resultMap> select * from t_emp where eid = #{eid} 一对多的映射处理一个部门对应多个员工，通过集合来表示部门中所有员工信息collection标签DeptMapper接口 /* 获取部门以及部门中所有的员工信息 */ public abstract Dept getDeptAndEmp(@Param("did") Integer did);DeptMapper.xml <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 * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did} 分步查询[video title="一对多分步查询 " url="https://img.kaijavademo.top/typecho/uploads/2023/08/videos/2023-08-22%2015-11-36.mkv " container="b4k5xtx7xcj" subtitle=" " poster=" "] [/video]DeptMapper.xml <resultMap id="deptAndEmpByStepResultMap" type="Dept"> <id property="did" column="did"></id> <result property="deptName" column="dept_name"></result> <collection property="emps" select="com.atguigu.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo" column="did" fetchType="eager"></collection> </resultMap> select * from t_dept where did = #{did} EmpMapper.xml <!--List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);--> select * from t_emp where did = #{did} 动态SQL多条件查询应该什么时候拼接SQL，使用java程序判断实现比较麻烦。mybatis为我们提供了一套动态文件的SQL，方便我们拼接SQL语句。本质就是一系列标签，帮助我们拼接SQL语句if标签根据标签中的test属性所对应的表达式决定标签中的内容是否需要拼接到SQL中写第一个条件判断之前需要加一个恒成立条件，防止第一个参数为null，语句拼接错误DynamicSQLMapper.xml <!--List<Emp> getEmpByCondition(Emp emp);--> select * from t_emp where 1=1 <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> <if test="email != null and email != ''"> and email = #{email} </if> where标签上面的if标签中where标签写死，所以说必须添加恒成立条件，还有一种情况就是where后面的条件均不成立，那么where多余了。如果说我们在上述使用where标签，可以帮助我们动态生成where关键字，并且可以将where标签体中的内容前面，多余的and去掉(or)。即使我们将条件均不成立，那么SQL语句将不会生成where。[font size="16" color="#ff0000"]注意：where标签不能将其中内容后面多余的and或or去掉[/font] select * from t_emp <where> <if test="empName != null and empName != ''"> emp_name = #{empName} </if> <if test="age != null and age != ''"> and age = #{age} </if> <if test="sex != null and sex != ''"> and sex = #{sex} </if> <if test="email != null and email != ''"> and email = #{email} </if> </where> trim标签若标签中有内容时：prefix|suffix:将trim标签中内容前面或后面添加指定内容prefixOverrides|suffixOverrides:将trim标签中内容前面或后面去掉指定内容若标签中没有内容时，trim标签也没有任何效果。DynamicSQLMapper.xml select * from t_emp <trim prefix="where" suffixOverrides="and|or"> <if test="empName != null and empName != ''"> emp_name = #{empName} and </if> <if test="age != null and age != ''"> age = #{age} or </if> <if test="sex != null and sex != ''"> sex = #{sex} and </if> <if test="email != null and email != ''"> email = #{email} </if> </trim> choose,when,otherwise标签相当于java中的if...else if...elsechoose是一个副标签，表示一个完整的if...else if...else结构when和if标签一样 <when test=""></when>when至少要有一个，otherwise最多只能有一个DynamicSQLMapper.xml <!--List<Emp> getEmpByChoose(Emp 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> did = 1 </otherwise> </choose> </where> foreach标签从浏览器中获取到的是一个数组，获取数据id实现批量删除。我们需要循环数组，获取数组中每个数据，然后在 where id IN (1,2,3) 就可以实现,或者使用or分隔语句进行删除。场景：通过数组实现批量删除，通过集合实现批量添加DynamicSQLMapper接口 /* 通过数组实现批量删除 */ public abstract int deleteMoreByArray(@Param("eids") Integer[] eids);测试类 @Test public void testDeleteMoreByArray(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class); int result = mapper.deleteMoreByArray(new Integer[]{6, 7, 8, 9, 10, 11}); System.out.println("result = " + result); }使用IN进行批量删除DynamicSQLMapper.xml <delete id="deleteMoreByArray"> delete from t_emp where eid in <foreach collection="eids" item="eid" separator="," open="(" close=")"> #{eid} </foreach> </delete> 使用or连接进行删除DynamicSQLMapper.xml <delete id="deleteMoreByArray"> delete from t_emp where <foreach collection="eids" item="eid" separator="or"> eid = #{eid} </foreach> </delete>场景：通过集合实现批量添加DynamicSQLMapper接口 /* 通过List集合实现批量添加的功能 */ public abstract int insertMoreByList(@Param("emps") List<Emp> emps);DynamicSQLMapper.xml <!--int insertMoreByList(@Param("emps") List<Emp> emps);--> <insert id="insertMoreByList"> insert into t_emp values <foreach collection="emps" item="emp" separator=","> (null,#{emp.empName},#{emp.age},#{emp.sex},#{emp.email},null) </foreach> </insert>SQL标签将我们常用的sql片段进行记录，在我们需要使用的地方，直接 [label color="red"]include[/label] 标签引用该片段。DynamicSQLMapper.xml <sql id="empColumns">eid,emp_name,age,sex,email</sql> <!--List<Emp> getEmpByCondition(Emp emp);--> select <include refid="empColumns"></include> from t_emp <trim prefix="where" suffixOverrides="and|or"> <if test="empName != null and empName != ''"> emp_name = #{empName} and </if> <if test="age != null and age != ''"> age = #{age} or </if> <if test="sex != null and sex != ''"> sex = #{sex} and </if> <if test="email != null and email != ''"> email = #{email} </if> </trim> 测试类所有源码public class DynamicSQLMapperTest { /* 动态SQL： 1.if:根据标签中的test属性所对应的表达式决定标签中的内容是否需要拼接到SQL中 2.where:当where标签中有内容时，会自动生成where关键字，并且将内容前多余的and或or去掉 当while标签中没有内容时，此时where标签没有任何效果 注意：where标签不能将其中内容后面多余的and或or去掉 3.trim: prefix|suffix:将trim标签中内容前面或后面添加指定内容 prefixOverrides|suffixOverrides:将trim标签中内容前面或后面去掉指定内容 4.choose,when,otherwise,相当于java中的if...else if...else when至少要有一个，otherwise最多只能有一个 5.foreach标签 collection：设置需要循环的数组或集合 item：表示数组或集合中的每一个数据 separator：循环体之间的分隔符 open：表示foreach标签所循环的所有内容的开始符号 close：表示foreach标签所循环的所有内容的结束符号 6.sql标签 将我们常用的sql片段进行记录 设置SQL片段：<sql id="empColumns">eid,emp_name,age,sex,email</sql> 引用SQL片段：<include refid="empColumns"></include> */ @Test public void testInsertMoreByList(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class); Emp emp1 = new Emp(null,"a1",23,"男","123@qq.com",null); Emp emp2 = new Emp(null,"a2",23,"男","123@qq.com",null); Emp emp3 = new Emp(null,"a3",23,"男","123@qq.com",null); List<Emp> emps = Arrays.asList(emp1, emp2, emp3); System.out.println(mapper.insertMoreByList(emps)); } @Test public void testDeleteMoreByArray(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class); int result = mapper.deleteMoreByArray(new Integer[]{6, 7, 8, 9, 10, 11}); System.out.println("result = " + result); } @Test public void testGetEmptyByChoose(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class); List<Emp> list = mapper.getEmpByChoose(new Emp(null, "张三", 23, "男", "123@qq.com", null)); System.out.println("list = " + list); } @Test public void testGetEmpByCondition(){ SqlSession sqlSession = SqlSessionUtils.getSqlSession(); DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class); List<Emp> emp = mapper.getEmpByCondition(new Emp(null, "张三", 23, "", "", null)); System.out.println("emp = " + emp); } }MyBatis的缓存一级缓存缓存就是把我们查询出来的数据进行记录，下次查询相同数据就从缓存中去取，就不会从数据库中访问。MyBatis会把我们查询的数据进行缓存，再次查询，如果缓存中有，就会从缓存中去取。MyBatis有一级缓存和二级缓存，一级缓存默认开启。一级缓存和二级缓存级别(范围)不一样，一级缓存范围是SqlSession级别的，同一个SqlSession查询出来的数据会被缓存，如果说再通过SqlSession查询相同数据就会从缓存中取。缓存只对查询功能有效范围、作用同一个SqlSession中，所查询的数据是会被缓存的，再一次获取缓存中的数据，会从缓存中调用。四种使一级缓存失效的情况不同的SqlSession对应不同的一级缓存，我们没有办法从同一个一级缓存中获取数据同一个SqlSession，但是查询条件不同，缓存应该是查询过的数据，新数据不会从缓存中取，而是从数据库中访问同一个SqlSession，两次查询操作期间执行了任意一次增删改操作，缓存会清空。增删改会改变数据库中的数据。缓存方便查询，提高查询效率，但是不能影响查询的结果，如果还从缓存中获取，那么结果将不准确。缓存只是为了提高速度，而不是影响真实性。同一个SqlSession，两次查询期间手动清空缓存 sqlSession1.clearCache();//使用此方法手动清空sqlsession的一级缓存 [label color="blue"]clearCache()[/label] 只对一级缓存有效二级缓存二级缓存的范围要比一级缓存的范围要大一点，二级缓存是是SqlSessionFactory级别，而且二级缓存需要手动开启。我们通过工厂创建的所有的SqlSession都属于二级缓存范围。[font size="16" color="7f00ff"]开启条件：[/font]在核心配置文件中，设置全局配置属性cacheEnabled="true"，默认为true，不需要设置在对应映射文件中设置标签二级缓存必须在SqlSession关闭或提交之后有效，什么叫关闭或提交？ sqlSession1.commit();//设置自动提交 sqlSession1.close();//关闭sqlSession在我们没有关闭或提交SqlSession，查询的数据会被保存到一级缓存中，当我们关闭或者提交SqlSession，数据才会保存到二级缓存中查询的数据所转换的实体类类型必须实现序列化的接口 public class Emp implements Serializable {}四个条件缺一不可。一种使二级缓存失效的情况两次查询之间执行了任意的增删改(实际上这个行为一级二级均会被清空)MyBatis缓存查询的顺序[note type="primary flat"]先查询二级缓存，二级缓存中可能会有其他程序已经查询出来的结果，可以直接使用如果二级缓存没有查到，查询一级缓存一级缓存没有命中，查询数据库SqlSession关闭之前，查询出来的数据默认保存在一级缓存中，SqlSession关闭之后，一级缓存中的数据会写入二级缓存。[/note]整合第三方缓存EHCache(会配就行)MyBatis从内存中读取要比磁盘文件中读取要快的很多，但是MyBatis毕竟作为持久层框架，在缓存功能的时候不是很专业，MyBatis提供了一些关于缓存的接口，可以由其他的技术作为MyBatis的二级缓存。只能使用其他第三方技术代替MyBatis的二级缓存，而一级缓存无法替代。pom文件中导入依赖 <dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.2.1</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency>创建EHCache的配置文件ehcache.xml（必须这样命名）<?xml version="1.0" encoding="utf-8" ?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <diskStore path="E:\atguigu\ehcache"/> <defaultCache maxElementsInMemory="1000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache>设置二级缓存的类型CacheMapper.xml <cache type="org.mybatis.caches.ehcache.EhcacheCache" />加入logback日志logback.xml<?xml version="1.0" encoding="UTF-8"?> <configuration debug="true"> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="STDOUT" /> </root> <logger name="com.atguigu.crowd.mapper" level="DEBUG"/> </configuration>MyBatis的逆向工程(☆)(☆)本质就是一个代码生成器正向工程：根据我们创建的java实体类，对应生成数据库表，Hibernate支持，而且帮助我们生成SQL语句。逆向工程：先创建数据库表，由当前的框架负责根据表生成实体类，mapper接口，映射文件。清新简洁版pom文件中添加依赖和插件<?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> <parent> <groupId>com.atguigu.mybatis</groupId> <artifactId>MyBatis</artifactId> <version>1.0-SNAPSHOT</version> </parent> <groupId>com.atguigu.mybatis</groupId> <artifactId>MyBatis_MBG</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </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>8.0.30</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.0</version> <dependencies> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.7</version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version> </dependency> </dependencies> </plugin> </plugins> </build> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> </project>创建核心配置文件包括导入jdbc.properties|log4j.xml|mybatis-config.xml创建逆向工程的配置文件 [label color="red"]文件名必须是generatorConfig.xml[/label]<?xml version="1.0" encoding="UTF-8"?> <generatorConfiguration> <context id="DB2Tables" targetRuntime="MyBatis3Simple"> <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="abc123"> <property name="nullCatalogMeansCurrent" value="true" /> </jdbcConnection> <javaModelGenerator targetPackage="com.atguigu.mybatis.pojo" targetProject=".\src\main\java"> <property name="enableSubPackages" value="true" /> <property name="trimStrings" value="true" /> </javaModelGenerator> <sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\resources"> <property name="enableSubPackages" value="true" /> </sqlMapGenerator> <javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\java"> <property name="enableSubPackages" value="true" /> </javaClientGenerator> </context> </generatorConfiguration>就可以自动生成我们需要的东西了，那么当然这种属于 [label color="blue"]清新简洁版[/label] ，只有增删改查五个方法 [label color="red"]配置文件中对于8+版本的MySQL需要多添加一行信息，防止重复生成所有表问题。[/label] <property name="nullCatalogMeansCurrent" value="true" />奢华尊享版(☆)调整修改targetRuntime <context id="DB2Tables" targetRuntime="MyBatis3"> 为MyBatis3就可以对于生成尊享版接口的一点点注解EmpMapper接口public interface EmpMapper { /*只要看到了方法名带有Example根据条件操作， 可以以任意字段，任意字段的所有需求作为条件 */ //根据条件来获取总记录数 int countByExample(EmpExample example); //根据条件进行删除 int deleteByExample(EmpExample example); //根据主键进行删除 int deleteByPrimaryKey(Integer eid); /*普通添加：如果当前传输实体类对象中某个属性的值是null， 那么我们的普通添加直接会把null作为值赋值给字段，*/ int insert(Emp record); /*选择性添加：只会将不是null的属性值为字段赋值，如果有空字段属性值， 那么就不会出现*/ int insertSelective(Emp record); //根据条件查询 List<Emp> selectByExample(EmpExample example); //根据主键查询 Emp selectByPrimaryKey(Integer eid); //根据条件选择性修改 这里的选择性：如果属性值为null，那么就不会去修改所对应的字段 int updateByExampleSelective(@Param("record") Emp record, @Param("example") EmpExample example); //根据条件修改 int updateByExample(@Param("record") Emp record, @Param("example") EmpExample example); //根据主键选择性修改 int updateByPrimaryKeySelective(Emp record); //根据主键修改 int updateByPrimaryKey(Emp record); } 不得不说，这样用起来真的巨方便，巨爽，我使用过程中目前出现了一个问题public class MBGTest { @Test public void testMBG(){ try { InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); //查询所有数据 List<Emp> list = mapper.selectByExample(null); list.forEach(emp -> System.out.println(emp)); } catch (IOException e) { e.printStackTrace(); } } } 测试类查询所有数据的时候[note type="warning flat"]org.apache.ibatis.exceptions.PersistenceException:\### Error querying database. Cause: java.sql.SQLException: Error setting driver on UnpooledDataSource. Cause: java.lang.ClassNotFoundException: Cannot find class: com.mysql.cj.jdbc.Driver[/note]我使用8+驱动任何地方都找遍了，我设置了 <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>的配置依然还是会报错，到目前还是没有找到解决办法。后面我在这篇CSDN中找到答案了非常感谢老哥解决出错，目前我没有找到太好的解决方法，手动导入了一个jar包(唉，都是会用maven的人了怎么又导包)后面查看Maven我大概知道了，主要是因为我把导入的依赖全部放在 [label color="red"]标签[/label] 下了，没有真正加载出来，所以说报错了。我调整了导入依赖的文件位置就发现好了测试类最终源码public class MBGTest { @Test public void testMBG(){ try { InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); EmpMapper mapper = sqlSession.getMapper(EmpMapper.class); //查询所有数据 /*List<Emp> list = mapper.selectByExample(null); list.forEach(emp -> System.out.println(emp));*/ /*根据条件查询 QBC风格，根据条件来查询 * 条件定义好的，只需要访问相对应的方法 * 就可以在相对应的SQL语句中生成对应条件 * */ //EmpExample example = new EmpExample(); //创建一个条件,可以使用链式编程添加条件 //example.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20); //通过or方法也可以使用or /*example.or().andDidIsNotNull(); List<Emp> list = mapper.selectByExample(example); list.forEach(emp -> System.out.println(emp));*/ //普通修改和选择性修改 //mapper.updateByPrimaryKey(new Emp(1,"admin",22,null,"456@qq.com",3)); //mapper.updateByPrimaryKeySelective(new Emp(1,"admin",22,null,"456@qq.com",3)); } catch (IOException e) { e.printStackTrace(); } } }分页插件分页功能可以在MyBatis设置一些相应的功能实现对应的分页，不需要通过书写SQL语句在pom文件中导入依赖 <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.2.0</version> </dependency>在核心配置文件中添加全局配置，配置插件mybatis-config.xml<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins> <?xml version="1.0" encoding="UTF-8" ?> <configuration> <properties resource="jdbc.properties"/> <typeAliases> <package name="com.atguigu.mybatis.pojo"/> </typeAliases> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins> <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.atguigu.mybatis.mapper"/> </mappers> </configuration>测试类测试我们在页面中设置相关的超链接，我们可以将PageInfo放在域对象中，然后在页面中进行访问。当我们有上一页/下一页我们才需要展示首页和尾页(使用关键字isFirstPage判断)。如果展示导航分页，将navigatepageNums数组进行循环，循环里面写超链接，展示页面，超链接上显示的哪一页就跳转到对应页面。在查询功能之前开启分页，在查询功能之后获取分页相关信息就行。[label color="blue"]常用数据：[/label]API功能pageNum当前页的页码pageSize每页显示的条数size当前页显示的真实条数total总记录数pages总页数prePage上一页的页码nextPage下一页的页码isFirstPage/isLastPage是否为第一页/最后一页hasPreviousPage/hasNextPage是否存在上一页/下一页navigatePages导航分页的页码数navigatepageNums导航分页的页码，[1,2,3,4,5]我书写这篇文章的初衷就是总结学习的进度，遗忘之际可以拿出来翻看，如有不对的地方还望指正，多多海涵。
作为java最流行的持久层技术，即学习完JDBC之后的另一门技术，以轻量级和性能出色的半自动成为了核心三大技术SSM中的之一。本篇文章是基于Mybatis的基础学习，包括框架的搭建，优化，还有工具类的封装和模板的添加。搭建MyBatis在pom依赖文件中添加打包方式为jar包 <packaging>jar</packaging>在依赖文件中导入依赖因为我的SQL版本是8+版本，所以导入对应版本的依赖,并添加log4j的日志文件(下面的文章中有提及，引入依赖还需要导入配置文件xml在resources下) <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>8.0.30</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies>核心配置文件创建核心配置文件对于一个框架，本质上来说就是 [label color="blue"]jar包 + 配置文件[/label] 文件没有默认的名字，但是建议是mybatis-config.xml,在整合SSM后，核心文件可以写可以不写，之后会交给Spring管理。 [label color="orange"]mybatis-config.xml[/label] ，核心配置文件应该创建在resources下<?xml version="1.0" encoding="UTF-8" ?> <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/mybatis"/> <property name="username" value="root"/> <property name="password" value="abc123"/> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers> </configuration>创建mapper接口(实现添加功能)Mybatis中的mapper接口相当于之前的DAO，以前的DAO有接口和实现类，而mapper只需要一个接口就可以，所谓面向接口编程。当我们通过mybatis中的方式去mapper创建接口对象，调用接口中的方法，就可以对应某个SQL语句。在接口中只需要添加操作数据库的方法即可。我们可以创建mapper接口，同DAO的命名，参考数据库表和实体类命名。映射文件尽量和我们的mapper接口名保持一致，只不过是一个xml文件。一个DAO类对应一个数据库表，一个mapper对应一个数据库表，一个mapper的映射文件对应一个mapper。 [label color="red"]MyBatis面向接口编程的两个一致：通过Mapper接口对应映射文件[/label]映射文件的namespace要和mapper接口的全类名保持一致映射文件中SQL语句的id要和mapper接口中的方法名一致UserMapper.xml<?xml version="1.0" encoding="UTF-8" ?> <mapper namespace="com.atguigu.mybatis.mapper.UserMapper"> <insert id="insertUser"> insert into t_user values(null,'admin','123456',23,'男','12345@qq.com') </insert> </mapper>UserMapper接口public interface UserMapper { /** MyBatis面向接口编程的两个一致：通过Mapper接口对应映射文件 1.映射文件的namespace要和mapper接口的全类名保持一致 2.映射文件中SQL语句的id要和mapper接口中的方法名一致 一个表 --- 实体类 --- mapper接口 --- 映射文件 */ /* 添加用户信息 */ public abstract int insertUser(); }修改核心配置文件mybatis-config.xml与对于配置文件产生关系 <mapper resource="mappers/UserMapper.xml"/> 在测试类中测试使用SQL在测试类中流程 @Test public void testMyBatis() throws IOException { /*MyBatis为我们提供了一个数据库的操作对象SqlSessionFactoryBuilder*/ //通过字节/字符输入流加载核心配置文件 InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); //获取SqlSessionFactoryBuilder SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); //获取sqlSessionFactoryBuilder的工厂对象,使用工厂模式 SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is); //获取SqlSession,代表Java程序和数据库之间的会话 SqlSession sqlSession = sqlSessionFactory.openSession(); //获取mapper接口对象。而现在mapper只有接口，如何获取实现类对象？ /*当我们传递进入一个类的class的对象，方法将获取该类型的实例化对象 getMapper底层帮助我们创建了该接口的实现类，并且返回了接口实现类对象 使用的是代理模式，帮助我们返回一个接口的实现类对象 */ UserMapper mapper = sqlSession.getMapper(UserMapper.class); //测试功能 int result = mapper.insertUser(); System.out.println("result = " + result);//result = 1 受影响的行数是1 //根据配置文件中事务管理方式，需要手动设置提交事务 sqlSession.commit(); }框架优化每次实现增删改查的时候都需要手动提交事务显得比较麻烦，可以把事务的提交设置成自动的。JDBC中事务就是自动提交，如果需要手动管理，才会关闭。 SqlSession sqlSession = sqlSessionFactory.openSession(true);添加日志功能使用的是 [label color="blue"]log4j[/label] ，添加依赖pom.xml <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> 添加配置文件log4j的配置文件名固定，大多数日志配置文件名都是固定的log4j.xml<?xml version="1.0" encoding="UTF-8" ?> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.PatternLayout"> </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>[note type="default flat"]日志的级别FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)从左到右级别越来越低，日志级别越高，输出信息越少；日志级别越低，输出信息越多；所选用的日志文件的级别输出信息≥本身级别信息。[/note]设置配置模板配置核心配置文件的模板通过设置IDEA配置模板的方式，可以增加我们开发的效率，不用每次核心配置文件去官方文档中或者是笔记里cv。spring-config.xml模板内容<?xml version="1.0" encoding="UTF-8" ?> <configuration> <properties resource="jdbc.properties"/> <typeAliases> <package name=""/> </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=""/> </mappers> </configuration>创建映射文件模板mybatis-mapper.xml模板内容<?xml version="1.0" encoding="UTF-8" ?> <mapper namespace=""> </mapper>以上两种模板在添加完成之后，以后的操作中只需要添加文件名，并在模板中补充对应的自定义的部分，附一张文件的存放位置。修改和删除功能在上面框架搭建过程中以及实现了添加功能，可以翻看。实际上我们书写增删改最好都使用这样的流程在接口(UserMapper)中添加对应抽象方法。 /* 修改用户信息 返回值可以写int 也可以不用传递返回值 */ public abstract void updateUser(); /* 删除用户信息*/ public abstract void deleteUser(); 复制返回值+方法名，在xml文件中添加注释并书写sql语句UserMapper.xml <update id="updateUser"> update t_user set username = '张三' where id = 4 </update> <delete id="deleteUser"> delete from t_user where id = 5 </delete>书写对应的测试类/类，创建对象，调用对应方法。 @Test public void testCRUD() throws IOException { InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); UserMapper mapper = sqlSession.getMapper(UserMapper.class); //修改功能 //mapper.updateUser(); //删除功能 mapper.deleteUser(); }查询功能查询功能不像是增删改，返回值固定。查询必定有返回值，考虑查询结果是什么？是一条数据，还是多条数据的实体类对象集合？单行单列？...查询一条数据|多条数据一条数据对应实体类对象，多条数据对应实体类集合UserMapper接口 /* 根据id查询用户信息 */ public abstract User getUserById(); /*查询所有的用户信息*/ public abstract List<User> getAllUser(); UserMapper.xml select * from t_user where id = 3 <!--List<User> getAllUser();--> select * from t_user 测试类 @Test public void testCRUD() throws IOException { InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); SqlSession sqlSession = sqlSessionFactory.openSession(true); UserMapper mapper = sqlSession.getMapper(UserMapper.class); //修改功能 //mapper.updateUser(); //删除功能 //mapper.deleteUser(); //查询一条语句 /* User user = mapper.getUserById(); System.out.println(user);*/ List<User> list = mapper.getAllUser(); //使用lambda遍历集合进行输出 list.forEach(user -> System.out.println(user)); }核心配置文件解读核心配置文件注释<?xml version="1.0" encoding="UTF-8" ?> <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/mybatis"/> <property name="username" value="root"/> <property name="password" value="abc123"/> </dataSource> </environment> </environments> <mappers> <mapper resource="mappers/UserMapper.xml"/> </mappers> </configuration>核心配置文件properties我们可以通过properties标签引入 [label color="orange"]properties文件[/label] ，通过 [label color="red"]${}[/label] 访问properties文件中的内容。jdbc.propertiesjdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis jdbc.username=root jdbc.password=abc123 对于核心配置文件稍作修改<?xml version="1.0" encoding="UTF-8" ?> <configuration> <properties resource="jdbc.properties"/> <environments default="development"> <environment id="development"> <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> <mapper resource="mappers/UserMapper.xml"/> </mappers> </configuration>类型别名及标签顺序每次配置查询语句的时候，都需要写 这样的标签，resultType后要加上全类名，很麻烦。而mybatis中为我们提供了类型别名的功能。 <properties resource="jdbc.properties"/> <typeAliases> <!--<typeAlias type="com.atguigu.mybatis.pojo.User" alias="User"></typeAlias>--> <package name="com.atguigu.mybatis.pojo"/> </typeAliases>核心配置文件mappers映射文件mybatis中支持以包为单位引入映射文件 <mappers> <!--<mapper resource="mappers/UserMapper.xml"/>--> <package name="com.atguigu.mybatis.mapper"/> </mappers>封装SqlSession工具类我们发现，添加了模板之后，在测试类中创建SqlSession尤为关键，那么创建SqlSession过程比较麻烦，我们可以封装一个工具类SqlSessionUtils类public class SqlSessionUtils { /*工具类中的方法一般都是静态方法,私有化构造方法*/ private SqlSessionUtils() { } public static SqlSession getSqlSession() { //读取核心配置文件，获取当前配置文件对应的字节输入流,用try-catch处理 SqlSession sqlSession = null; try { InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); //通过创建出来的sqlSession实现增删改可以自动提交 sqlSession = sqlSessionFactory.openSession(true); } catch (IOException e) { e.printStackTrace(); } return sqlSession; } }然后可以在测试类中使用，直接就可以得到sqlSession.获取参数值的两种方式(☆☆)观察到语句都是自己手动输入的值，以后mybatis会放到ssm中一块使用，需要去创建一个web工程，浏览器发送请求之后到服务器，服务器接收请求参数调用service处理业务逻辑，service调用dao(现在通过mapper接口代替dao)，service调用的mapper方法将当前浏览器获取的数据传输到映射文件中。映射文件该如何获取所传输的参数(获取的参数值是我们所调用的mapper接口中方法的参数，我们需要在映射文件中获取)，实现SQL语句的拼接？ [label color="blue"]MyBatis获取参数值的两种方式：${} 和 #{}[/label] 分别对应了JDBC中的两种方式${} 本质就是字符串拼接，有sql注入的问题，有一些sql必须使用。\#{} 本质就是占位符赋值。根据不同情况参数值的获取也不同。我将这五种情况对应的总结笔记放置在最上面，下面是对应的书写案例[note-ico type="flat" ico=""]MyBatis获取参数值的各种情况：mapper接口方法的参数为单个的字面量类型：可以通过${}和#{}以任意的字符串获取参数值，但是需要注意${}的单引号问题如果当前的mapper接口方法的参数为多个时：此时MyBatis会将这些参数放在一个map集合中，以两种方式进行存储a> 以arg0，arg1...为键，以参数为值b> 以param1，param2...为键，以参数为值因此只需要通过#{}和 ${}以键的方式访问值即可，需要注意${}的单引号问题若mapper接口方法的参数是一个map集合，可以手动将这些参数放在一个map中来存储因此只需要通过#{}和 ${}以键的方式访问值即可，需要注意${}的单引号问题mapper接口方法的参数是一个实体类类型的参数只需要通过#{}和 ${}以属性的方式访问属性值即可，但是需要注意${}的单引号问题使用@Param注解命名参数此时MyBatis会将这些参数放在一个map集合中，以两种方式进行存储a> 以@Param注解的值为键，以参数为值b> 以param1，param2...为键，以参数为值因此只需要通过#{}和 ${}以键的方式访问值即可，需要注意${}的单引号问题[/note-ico][font size="16" color="#ff0000"]实际上还有很多情况，包括数组集合，一共是七种情况，建议归结为两种[/font]实体类对象/map集合 的情况除实体类对象/map集合情况，手动添加 [label color="orange"]@Param注解[/label] 的情况获取单个字面量类型的参数ParameterMapper.xml select * from t_user where username = '${username}' @Test public void testGetUserByUsername() { SqlSession sqlSession = SqlSessionUtils.getSqlSession(); //通过接口获取到一个mapper实体类的对象 ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class); User user = mapper.getUserByUsername("admin"); System.out.println(user); } 获取多个字面量类型的参数 select * from t_user where username = '${param1}' and password = '${param2}' 获取Map类型的参数 <!--User checkLoginByMap(Map<String, Object> map);--> select * from t_user where username = #{username} and password = #{password} 获取实体类类型参数此处的username、password、age、sex、email均属于set方法后对应名称的小写。 <insert id="insertUser"> insert into t_user values (null,#{username},#{password},#{age},#{sex},#{email}) </insert> @Param命名参数注解自定义当前mybatis把参数存储在map集合的键ParameterMapper接口 /* 验证登录（使用@Param注解） 当我们在参数前添加@Param注解，Mybatis会帮我们把参数放在一个map集合中， 以@Param中的参数为键，以形参为值。 */ public abstract User checkLoginByParam(@Param("username") String username, @Param("password") String password); select * from t_user where username = #{username} and password = #{password} 我书写这篇文章的初衷就是总结学习的进度，遗忘之际可以拿出来翻看，如有不对的地方还望指正，多多海涵。列表项目