标签:姓名 忽略 sel 数组 art catch 帮助 存在 ssi
本篇篇幅较长,请善用 Ctrl + F 搜索功能。
结尾补充了 MyBatis 中 resultMap 的映射级别。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
MyBatis学完也有几天了,总结一下学习到的内容,也算是复习了。
使用MyBatis之前,我们要知道,什么是MyBatis?
MyBatis是apache一个开源的,基于Java的持久层框架。
MyBatis的优点有哪些?
学习简单,提供半自动的关系映射,SQL语句与代码分离。
MyBatis的缺点又有哪些?
要会写SQL语句;每个数据库的SQL语句都多少会有偏差,所以不方便更换数据库。
MyBatis适合什么样的项目?
适合性能要求很高,或者需要变化较多的项目。
要使用MyBatis,得有MyBatis的jar包。
在https://github.com/mybatis/mybatis-3/releases下载mybatis-x.x.x.zip,我用的版本是3.3.2。
压缩包里的mybatis-x.x.x.jar就是我们要的jar包了,.pdf的是帮助文档,lib文件夹里的是MyBatis的依赖包,具体作用自行百度,一起丢到项目的lib的文件夹里全部add build一下就行了。
哦对了,jdbc的jar包请自行准备。
只有jar包还不够,我们还需要xml配置文件。
新建一个Source Folder,将配置文件统一放在里面。为了方便识别,MyBatis的配置文件我们可以命名为“mybatis-config.xml”,配置文件的内容大致是这样的,改改就能用:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <configuration> 6 <properties resource="mybatis.properties" /><!-- jdbc配置文件 --> 7 <typeAliases><!-- 类型别名 --> 8 <typeAlias type="cn.bwm.pojo.User" alias="User"/><!-- 给指定的类起一个别名 --> 9 <package name="cn.bwm.pojo" /><!-- 给包里的所有类起一个和类名一样的别名 --> 10 </typeAliases> 11 <environments default="test"><!-- 配置环境 ,default选择默认配置--> 12 <environment id="test"><!-- 环境元素 --> 13 <transactionManager type="JDBC" /> <!-- 配置事务管理器 --> 14 <dataSource type="POOLED"><!-- 数据源 --> 15 <property name="driver" value="${driver}" /><!-- jdbc配置文件对应属性 --> 16 <property name="url" value="${url}" /> 17 <property name="username" value="${username}" /> 18 <property name="password" value="${password}" /> 19 </dataSource> 20 </environment> 21 </environments> 22 <mappers><!-- 映射器 --> 23 <mapper resource="cn/bwm/dao/IUserMapper.xml" /><!-- xml映射文件 --> 24 </mappers> 25 </configuration>
每个标签的具体作用请参考官方文档,中文的,http://www.mybatis.org/mybatis-3/zh/getting-started.html。
最后一步也是举足轻重的一步,配置MyBatis的两个dtd文件。
这两个文件,一个叫“mybatis-3-config.dtd”,另一个叫“mybatis-3-mapper.dtd”,我们可以通过解压缩mybatis-x.x.x.jar,在\org\apache\ibatis\builder\xml 这个目录下找到这两个文件。
我用的是MyEclipse10.6,配置的步骤是:
Windows → Preferences ; 选择XML Catalog ,选择User Specified Entries,单击 Add ; 单击 File System 后选择dtd文件, Key填写 -//mybatis.org//DTD Config 3.0//EN (与MyBatis-config.xml文件投中的 -//mybatis.org//DTD Config 3.0//EN 相同)。
两个dtd文件配置步骤一样,配置完成以后,在MyBatis-config.xml文件和xml映射文件中就可以使用 alt + / 自动联想了。
完成以上步骤以后,MyBatis就算是部署到项目中了,至于如何使用MyBatis,我们还需要准备一个数据库。这个数据库至少要有两张结构简单有主外键关系的表,以及少量数据。在项目中创建与数据库的表对应的实体类,在数据访问层创建实体类对应的接口,并声明抽象方法,例如:
/** * 老师类 * @author Administrator * */ public class Teacher { private int id; private String name; private Student student; private List<Student> studentList; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Student getStudent() { return student; } public void setStudent(Student student) { this.student = student; } public List<Student> getStudentList() { return studentList; } public void setStudentList(List<Student> studentList) { this.studentList = studentList; } } /** * 学生类 * @author Administrator * */ public class Student { private int id; private String name; private int tid; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getTid() { return tid; } public void setTid(int tid) { this.tid = tid; } } /** * Teacher实体类的对应接口 * @author Administrator * */ public interface ITeacherMapper { /** * 根据id查询老师 * @param id * @return Teacher对象 */ public Teacher queryTeacherById(int id); }
在接口的同目录下创建同名xml文件:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="cn.bwm.dao.ITeacherMapper"> 6 <select id="queryTeacherById" parameterType="int" resultType="Teacher"> 7 SELECT `Id`,`Name` FROM `teacher` WHERE `Id` = #{id} 8 </select> 9 </mapper>
写完这些代码和配置文件,现在,我们再来简单了解一下MyBatis的核心接口和类:
深入了解请查看官方文档,中文的, http://www.mybatis.org/mybatis-3/zh/java-api.html 。
根据三个核心接口和类,我们再写一个用来获取SqlSession对象的工具类:
1 public class SqlSessionUtil { 2 private static SqlSessionFactory sqlSessionFactory; 3 4 static{ 5 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); 6 try { 7 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); 8 sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); 9 } catch (IOException e) { 10 e.printStackTrace(); 11 } 12 } 13 14 /** 15 * 获取SqlSession对象 16 * @return 17 */ 18 public static SqlSession getSqlSession(){ 19 return sqlSessionFactory.openSession(); 20 } 21 22 /** 23 * 关闭SqlSession对象 24 * @param sqlSession 25 */ 26 public static void closeSqlSession(SqlSession sqlSession){ 27 if (sqlSession != null) { 28 sqlSession.close(); 29 } 30 } 31 }
现在,我们可以写测试代码了:
1 public class Test { 2 public static void main(String[] args) { 3 SqlSession sqlSession = SqlSessionUtil.getSqlSession(); 4 Teacher teacher = sqlSession.getMapper(ITeacherMapper.class).queryTeacherById(1); 5 System.out.println("编号:" + teacher.getId() + "\t姓名:" + teacher.getName()); 6 SqlSessionUtil.closeSqlSession(sqlSession); 7 } 8 }
相信大家也看出来了,我们使用MyBatis执行了简单的查询操作,并将结果封装成了一个对象,而这其中的关键就在于与接口同名的xml映射文件。
我们来看一下映射文件中用到了哪些元素:
我们在查询的时候,不可能只有单参数查询,而parameterType只能写一个类型,这个时候,有三种方法:
先说第一种,使用对象作为参数。这种方法应该比较适合插入操作,我们这里强行使用一波。
先在接口里写上方法:
1 /** 2 * 根据编号和姓名查询老师 3 * @param t Teacher对象 4 * @return Teacher对象 5 */ 6 public Teacher queryTeacherByIdName(Teacher t);
在xml映射文件里写对应的SQL语句,parameterType写的是参数类型 Teacher,#{id}和#{name}都是 Teacher 类的属性,CONCAT()是MySQL的函数,用来拼接字符串:
1 <select id="queryTeacherByIdName" parameterType="Teacher" resultType="Teacher"> 2 SELECT `Id`,`Name` FROM `teacher` WHERE `Id` = #{id} AND `Name` LIKE CONCAT(‘%‘ , #{name} , ‘%‘) 3 </select>
测试代码是这样的:
1 public static void main(String[] args) { 2 SqlSession sqlSession = SqlSessionUtil.getSqlSession(); 3 Teacher t = new Teacher(); 4 t.setId(1); 5 t.setName("小"); 6 Teacher teacher = sqlSession.getMapper(ITeacherMapper.class).queryTeacherByIdName(t); 7 System.out.println("编号:" + teacher.getId() + "\t姓名:" + teacher.getName()); 8 SqlSessionUtil.closeSqlSession(sqlSession); 9 }
这样便完成了使用对象作为参数来进行查询的操作。
然后是第二种,将参数封装成Map集合,我们修改一下刚才的方法,把参数改成 Map<String , Object>集合:
1 /** 2 * 根据编号和姓名查询老师 3 * @param map Map<String,Object>集合 4 * @return Teacher对象 5 */ 6 public Teacher queryTeacherByIdName(Map<String,Object> map);
xml映射文件里,parameterType改成了 map,是MyBatis提供的别名:
1 <select id="queryTeacherByIdName" parameterType="map" resultType="Teacher"> 2 SELECT `Id`,`Name` FROM `teacher` WHERE `Id` = #{id} AND `Name` LIKE CONCAT(‘%‘ , #{name} , ‘%‘) 3 </select>
测试代码把刚才作为参数的 Teacher 对象改成 Map<String , Object>集合:
1 public static void main(String[] args) { 2 SqlSession sqlSession = SqlSessionUtil.getSqlSession(); 3 Map<String,Object> map = new HashMap<String,Object>(); 4 map.put("id", 1); 5 map.put("name", "小"); 6 Teacher teacher = sqlSession.getMapper(ITeacherMapper.class).queryTeacherByIdName(map); 7 System.out.println("编号:" + teacher.getId() + "\t姓名:" + teacher.getName()); 8 SqlSessionUtil.closeSqlSession(sqlSession); 9 }
这样就完成了使用 Map 传递多个参数。
最后是第三种,使用@Param注解,还是直接修改刚才的方法,把 Map<String , Object> 换成 @Param 注解的参数:
1 /** 2 * 根据编号和姓名查询老师 3 * @param id 编号 4 * @param name 姓名 5 * @return Teacher 对象 6 */ 7 public Teacher queryTeacherByIdName(@Param("tid")int id , @Param("tname")String name);
xml文件里,因为@Param("")里写的是 tid 和 tname,所以 #{} 也要写的一样:
1 <select id="queryTeacherByIdName" parameterType="map" resultType="Teacher"> 2 SELECT `Id`,`Name` FROM `teacher` WHERE `Id` = #{tid} AND `Name` LIKE CONCAT(‘%‘ , #{tname} , ‘%‘) 3 </select>
测试代码里,参数也不用放在 Map 集合里了:
1 public static void main(String[] args) { 2 SqlSession sqlSession = SqlSessionUtil.getSqlSession(); 3 Teacher teacher = sqlSession.getMapper(ITeacherMapper.class).queryTeacherByIdName(1 , "小"); 4 System.out.println("编号:" + teacher.getId() + "\t姓名:" + teacher.getName()); 5 SqlSessionUtil.closeSqlSession(sqlSession); 6 }
这就是 @Param 的使用方法。
三种方法说完了,但不管参数有多少,我们现在查询的结果都只是一个简单对象,如果结果的类型包含另一个类型,或者包含一个集合,这里我们就要了解一下 <resultMap> 元素及其子元素 <result>、<association> 和 <conllection> 。
我们通过代码来讲解这几个个元素的使用方法,我的 Teacher 类中已经有一个 Student 属性和一个 List<Student> 属性:
1 /** 2 * 老师类 3 * @author Administrator 4 * 5 */ 6 public class Teacher { 7 private int id; 8 private String name; 9 private Student student; //学生对象 10 private List<Student> studentList; //学生集合 11 //省略 getset 方法 12 }
接口里的方法可以不用修改,xml映射文件需要大改一下:
1 <select id="queryTeacherByIdName" resultMap="query"> 2 select t.`Id` as tid , t.`Name`as tname , s.`Id` as sid , s.`Name` as sname from `teacher` as t 3 inner join `student` as s on s.`Tid` = t.`Id` where t.`Id` = #{tid} 4 </select> 5 <resultMap type="Teacher" id="query"> 6 <id column="tid" property="id"/> 7 <result column="tname" property="name"/> 8 <association property="student" javaType="Student"> 9 <id column="sid" property="id"/> 10 <result column="sname" property="name"/> 11 <result column="tid" property="tid"/> 12 </association> 13 <collection property="studentList" ofType="Student"> 14 <id column="sid" property="id"/> 15 <result column="sname" property="name"/> 16 <result column="tid" property="tid"/> 17 </collection> 18 </resultMap>
select 标签的 resultType 属性换成了 resultMap属性,值与 resultMap 标签的 id 一样。
另外,resultMap 结果映射可以复用,我们改一下xml映射文件的代码:
1 <select id="queryTeacherByIdName" resultMap="query1"> 2 select t.`Id` as tid , t.`Name`as tname , s.`Id` as sid , s.`Name` as sname from `teacher` as t 3 inner join `student` as s on s.`Tid` = t.`Id` where t.`Id` = #{tid} 4 </select> 5 6 <resultMap type="Student" id="student"> 7 <id column="sid" property="id"/> 8 <result column="sname" property="name"/> 9 <result column="tid" property="tid"/> 10 </resultMap> 11 12 <resultMap type="Teacher" id="query1"> 13 <id column="tid" property="id"/> 14 <result column="tname" property="name"/> 15 <association resultMap="student" property="student" javaType="Student"/> 16 </resultMap> 17 18 <resultMap type="Teacher" id="query2"> 19 <id column="tid" property="id"/> 20 <result column="tname" property="name"/> 21 <collection resultMap="student" property="studentList" ofType="Student"/> 22 </resultMap>
在代码里,两个 resultMap 里的 association 和 collection 都重用了 query 这个 resultMap ,可以节省不少代码。顺便一提,我在测试时,association 和 collection 无法在一个 resultMap 里重用同一个 resultMap ,collection 会失效,最终查询出来的结果,List的元素数量是0,具体原因暂时还没找到。
查询部分算是结束了,接下是比较简单的增删改操作,先在接口里写上对应的方法:
1 /** 2 * 增加老师 3 * @param teacher Teacher对象 4 * @return 5 */ 6 public int addTeacher(Teacher teacher); 7 8 /** 9 * 修改老师 10 * @param teacher Teacher对象 11 * @return 12 */ 13 public int updateTeacher(Teacher teacher); 14 15 /** 16 * 根据id删除老师 17 * @param id 老师的编号 18 * @return 19 */ 20 public int deleteTeacher(int id);
xml映射文件里也要使用对应的标签,分别是 <insert>、<update>和<delete>:
1 <insert id="addTeacher" parameterType="Teacher"> 2 INSERT INTO `teacher`(`Name`) VALUES(#{name}) 3 </insert> 4 5 <update id="updateTeacher" parameterType="Teacher"> 6 UPDATE `teacher` SET `Name` = #{name} WHERE id = #{id} 7 </update> 8 9 <delete id="deleteTeacher" parameterType="int"> 10 DELETE FROM `teacher` WHERE `Id` = #{id} 11 </delete>
因为增删改的操作返回的是数据库受影响的行数,所以这个三个标签是没有 resultType 和 resultMap 两个属性的。
测试部分需要增加一点点代码:
1 /** 2 * 添加老师 3 */ 4 private static void addTeacher() { 5 SqlSession sqlSession = SqlSessionUtil.getSqlSession(); 6 Teacher teacher = new Teacher(); 7 teacher.setName("小黑白"); 8 int result = sqlSession.getMapper(ITeacherMapper.class).addTeacher(teacher); 9 if (result > 0) { 10 sqlSession.commit(); //提交事务 11 System.out.println("添加成功!"); 12 }else{ 13 System.out.println("添加失败!"); 14 } 15 SqlSessionUtil.closeSqlSession(sqlSession); 16 } 17 18 /** 19 * 修改老师 20 */ 21 private static void updateTeacher() { 22 SqlSession sqlSession = SqlSessionUtil.getSqlSession(); 23 Teacher teacher = new Teacher(); 24 teacher.setId(2); 25 teacher.setName("小黑"); 26 int result = sqlSession.getMapper(ITeacherMapper.class).updateTeacher(teacher); 27 if (result > 0) { 28 sqlSession.commit(); //提交事务 29 System.out.println("修改成功!"); 30 }else{ 31 System.out.println("修改失败!"); 32 } 33 SqlSessionUtil.closeSqlSession(sqlSession); 34 } 35 36 /** 37 * 根据id删除老师 38 */ 39 private static void deleteTeacher() { 40 SqlSession sqlSession = SqlSessionUtil.getSqlSession(); 41 int result = sqlSession.getMapper(ITeacherMapper.class).deleteTeacher(2); 42 if (result > 0) { 43 sqlSession.commit(); //提交事务 44 System.out.println("删除成功!"); 45 }else{ 46 System.out.println("删除失败!"); 47 } 48 SqlSessionUtil.closeSqlSession(sqlSession); 49 }
这三个操作都有一个共同的特点,就是在判断数据库受影响的行数大于0以后,都会调用 SqlSession 的 commit() 方法。
这是因为 MyBatis 在执行增删改操作的时候并没有直接操作数据库,我们可以理解成是在操作一个虚拟的数据库,当我们调用 commit() 方法后,我们所做的操作才会对真正的数据库产生影响。
以上就是使用 MyBatis 对数据库进行增删改查操作的示例,我们不难发现,把 SQL语句写在 xml映射文件里会导致我们无法用代码改变 SQL 语句,显得不够灵活,对此,MyBatis为我们提供了动态SQL。
动态SQL是MyBatis的一个强大的特性,基于 OGNL 的表达式,使我们可以方便的动态改变 SQL 语句。
用于动态SQL的元素有:
假设,我们使用 id 和 name 来查询老师,如果 name 没有传入参数,就只用 id 查询老师,这时候就可以使用 if 来进行判断:
1 <select id="queryTeacher" parameterType="map" resultType="Teacher"> 2 SELECT * FROM `teacher` 3 WHERE `Id` = #{id} 4 <if test="name != null and name != ‘‘"> 5 AND `Name` LIKE CONCAT(‘%‘ , #{name} , ‘%‘) 6 </if> 7 </select>
test 属性其他标签也有,用来判断条件。
再假设,id 和 name 只要有其中一个就可以了,按照有条件进行查询,如果没有就查询全部,这时可以使用 choose 和 它的子元素 when、otherwise来实现:
1 <select id="queryTeacher" parameterType="map" resultType="Teacher"> 2 SELECT * FROM `teacher` 3 WHERE 4 <choose> 5 <when test="id != null and id != 0"> 6 `Id` = #{id} 7 </when> 8 <when test="name != null and name != ‘‘"> 9 `Name` = #{name} 10 </when> 11 <otherwise> 12 1 = 1 13 </otherwise> 14 </choose> 15 </select>
choose 相当于 Java 中的 switch 语句,从上向下开始判断,只要有 when 的 test 成立,就返回该 when 里的 SQL 语句并跳出 choose,如果所有的 when 都不成立,就返回 otherwise 里的SQL语句。因为是从上向下判断的,所以要注意 SQL 语句的优先顺序。
还有最后的 otherwise 里的 1 = 1,如果没有这个的话,很有可能因为 id 和 name 两个都没有参数而造成 where 后面什么都没有,造成 SQL 语句报错。这时,就需要使用 trim元素,它可以灵活的去除多余的关键字:
1 <select id="queryTeacher" parameterType="map" resultType="Teacher"> 2 SELECT * FROM `theacher` 3 <trim prefix="WHERE" prefixOverrides="and | or"> 4 <if test="id != null and id != 0"> 5 AND `id` = #{id} 6 </if> 7 <if test="name != null and name != ‘‘"> 8 AND `name` = #{name} 9 </if> 10 </trim> 11 </select>
trim 元素会自动识别标签内是否有返回值,有的话就在内容的前面加上 prefix 属性的值 where,并忽略 prefixOverrides 里所包含的内容 and 和 or 。(这部分代码只为了展示 trim 的作用,请忽略代码的意义)
这部分的 trim 的使用等价于 where 标签:
1 <select id="queryTeacher" parameterType="map" resultType="Teacher"> 2 SELECT * FROM `theacher` 3 <where> 4 <if test="id != null and id != 0"> 5 AND `id` = #{id} 6 </if> 7 <if test="name != null and name != ‘‘"> 8 AND `name` = #{name} 9 </if> 10 </where> 11 </select>
trim 不仅可以在 SQL 语句前添加内容和忽略内容,也可以在 SQL 语句后追加内容和忽略内容,例如刚才的修改操作:
1 <update id="updateTeacher" parameterType="Teacher"> 2 UPDATE `teacher` SET `Name` = #{name} WHERE id = #{id} 3 <trim prefix="Set" suffixOverrides="," suffix="WHERE id = #{id}"> 4 <if test="id != null"> 5 `id` = #{id} , 6 </if> 7 <if test="name != null"> 8 `name` = #{name} , 9 </if> 10 </trim> 11 </update>
使用 prefix 在 SQL 语句前加上 prefix 的值 Set, 在 SQL 语句的最后加上 suffix 的值 WHERE id = #{id},忽略 SQL 语句最后的 suffixOverrides 的值 , 。(这段代码只展示了 trim 的作用,请无视不合理的部分)
这部分 trim 的使用等价于 set 标签:
1 <update id="updateTeacher" parameterType="Teacher"> 2 UPDATE `teacher` SET `Name` = #{name} WHERE id = #{id} 3 <set> 4 <if test="id != null"> 5 `id` = #{id} , 6 </if> 7 <if test="name != null"> 8 `name` = #{name} , 9 </if> 10 </set> 11 WHERE `id` = #{id} 12 </update>
不过 WHERE 需要自己写。
另外,prefix、perfixOverriders、suffix 和 suffixOverriders四个属性是可以同时使用的,根据时间情况选择。
foreach 元素,用于循环集合,主要用于构建 IN 条件语句的时候使用:
1 <select id="queryTeacher" resultType="Teacher"> 2 SELECT * FROM `theacher` 3 WHERE `id` IN 4 <foreach collection="list" item="id" index="index" open="(" separator="," close=")"> 5 #{id} 6 </foreach> 7 </select>
这里我们迭代了 list 集合,collection 属性表示迭代时每个元素的别名;index 表示每次迭代到的位置;open 表示 SQL 语句以什么开始;separator 表示每次迭代直接用什么进行分隔;close 表示 SQL 语句以什么结束;collection 必须指定,对应要遍历的集合。
在遍历 对象 和 数组时,index 表示当前迭代的次数,item 的值是表示当前迭代获取的元素。
遍历 Map 时,index 是键, item 是值。
补充一下 resultMap 的映射级别。
我在使用 resultMap 自定义映射结果的时候发现,即使我只在 resultMap 里定义一个 id ,其他的属性也还是会自动映射上去。
这是因为 MyBatis 的配置文件中,autoMappingBehavior 的默认级别是 PARTIAL,只会自动映射没有定义嵌套结果集映射的结果集,改成 NONE 就可以取消自动映射,改成FULL的话,会自动映射复杂的结果集,无论是否嵌套。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
到这里,关于MyBatis我所学习到的内容就全部结束了。
第一次写博客没有经验,写的很长,也很烂。
感谢耐心看到这里的你,如果对你有所帮助就再好不过了。
标签:姓名 忽略 sel 数组 art catch 帮助 存在 ssi
原文地址:https://www.cnblogs.com/BWMaple/p/9201802.html