Mybatis 整理

1.环境准备

  1. _无论是用maven或者是jar包,我们都应该先了解什么是Mybatis,通俗一点来讲,Mybatis 就是一个用来代替JDBC的框架,简化了DAO层,用一个Mapper.XML代替了我们之前繁琐的重写或者新写一堆无意义的methodclass。如果说是用正常的jar包,我们需要到github中搜索Mybatis3,进入其中寻找到我们需要的 Jar包,回来放入项目中的 lib文件夹下就好了。如果说是Maven项目,我们首先要创建Maven依赖,Maven这部分还没有学 ,后续进行了解,我们需要2 Jar包,分别是对应着我们本地的Mysqlconnector 8.0与我们的MybatisJar包,导入之后,我们为了避免出现一系列的找不到资源文件的bug,直接在Maven文件下复制这样一段话,这里如果说添加后仍然找不到对应资源,就看看有没有刷新Maven_
  1. <build>
  2. <resources>
  3. <resource>
  4. <directory>src/main/java</directory>
  5. <includes>
  6. <include>**/*.properties</include>
  7. <include>**/*.xml</include>
  8. </includes>
  9. </resource>
  10. <resource>
  11. <directory>src/main/resources</directory>
  12. <includes>
  13. <include>**/*.*</include>
  14. </includes>
  15. </resource>
  16. </resources>
  17. </build>

完成了这部分,我们就可以开始进行Mybatis的配置了

2.第一个MyBatis项目

  1. _首先进行XML文件的相关配置,在resources文件夹下创建Mybatis-configuration.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="db.properties"></properties>
  7. <environments default="development">
  8. <environment id="development">
  9. <transactionManager type="JDBC"/>
  10. <dataSource type="POOLED">
  11. <property name="driver" value="${driver}"/>
  12. <property name="url" value="${url}"/>
  13. <property name="username" value="${user}"/>
  14. <property name="password" value="${psw}"/>
  15. </dataSource>
  16. </environment>
  17. </environments>
  18. <mappers>
  19. <mapper resource="com/zjl/mybatis/mapper/mapper.xml"></mapper>
  20. </mappers>
  21. </configuration>

解读:

  1. _我们主要需要进行改动的位置就是标签中的信息。第一个标签是properties,这个标签是属性标签,可以用来加载我们的db.properties文件,或者说,我们可以在标签内部写上单个property进行属性的赋值,在使用时,我们如果希望调用属性内的值,就 ${key} 这样将propertykey放入其中即可_
  1. <properties resource="db.properties">
  2. <property name="name" value="test"/>
  3. </properties>
  1. _第二个标签是enviroments标签。这是环境标签,便于我们在开发是更换不同的环境,数据库等等。更换的方式是将default中的名称换成对应的enviroment标签中的id值。对于内部的transactionManager是配置数据库的事务处理,这里与我们Mysql不同的是,我们使用Mybatis进行数据库的表中信息进行删改增时,务必要进行事务提交,不然是无法更新数据库的。接着的datasource我们可以理解为这是链接数据库的操作,我们配置其中的driverpassworduserurl,等等信息进行数据库的连接。对于mapper标签这是对于dao层进化为mapper层的一个全新的配置。我们把mapper.xml配置到Mybatis的核心配置文件中,mapper才能够执行其相关的功能。到现在我们就大致构建好了Mybatis的配置文件,接下来我们来尝试使用Mybatis进行增删改查!_

3.Mybatis的mapper

Mybatis的一大优点我觉得就是用XML文件来代替了各种实现类的书写,但是其中奥妙还需要逐步的学习体会,先看一下如何进行mapper 的编写吧,mapper是改造了dao层,原来的dao层是通过dao接口和daoImpl类进行sql查询和结果集的处理。在mapper中,我们需要构建一个mapper接口(这就是面向接口编程???)这个接口集合basedao一样,里面声明好各种相应的增删改查方法。如下就是进行一个返回全部用户的查询结果

  1. public interface mapper {
  2. List<user> getuserlist();
  3. }

如果按照常规的编程思想,我们回去写实现类,写入sql语句,参数等等

但是在Mybatis中这些都不是必要的,其实在这里我个人认为Mybatis的不仅是简化了编程,一定程度上还可以让不会编程的人也能看懂编程,降低了编程的门槛,回归正题,在Mybatis中,我们需要做的是,在这个interface所在的包目录下,创建一个和接口名称相同的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="com.zjl.mybatis.mapper.mapper">
  6. <select id="getuserlist" resultType="user">
  7. select * from user
  8. </select>
  9. </mapper>

解读:

这段代码中主要有一下几个要素点

1.namespace 这是表示对应的interface类,通过输入准确的全类名来将interface 和同名的XML配置文件进行绑定;

2.select标签,这里只是展示了一种,除了select还有update,insert,delete这三种,不过我们主要关注一下select,因为select相比于其他有个特殊的点就是select一般都会有返回的resultset,所以我们需要去承接这个返回的结果的列名和数据,所以一般要以对象和属性的形式进行数据的保存,故需要确定封装数据的类型!而因为update insert delete 是没有返回对应结果集的,所以不会有这一选项。

声明承接数据的标签有resultType和resultMap 2种 ,后者是对于前者的拓展,因为我们在开发中很可能会出现一些其他的情况,例如我们的pojo类中property和Database中的字段名并不完全匹配,所以我们会采取这一手段,使用如下

  1. <mapper namespace="com.zjl.mybatis.mapper.mapper">
  2. <resultMap id="user" type="com.zjl.mybatis.pojo.user">
  3. <result column="psw" property="password"></result>
  4. </resultMap>
  5. <select id="getuserlist" resultMap="user">
  6. select * from user
  7. </select>
  8. </mapper>

在这里我们就可以实现相应字段和属性的匹配,但是有一个问题是不会有这么傻逼的开发者,所以说resultMap的用法还没有正式开始

上面说完了select中特有的声明封装返回结果类型标签,然后来看CRUD都有几个标签

1.parameterType 这里用来声明我们传入参数的类型,如果说有多个参数可以使用对象类来进行封装,或者使用Map来存储参数,注入sql时取出其中的key就可以了!这里就举一个比较简单的例子看看吧!

  1. <select id="getuser" parameterType="com.zjl.mybatis.pojo.user" resultType="user">
  2. select * from user where name =#{name};
  3. </select>

2.id 这里的id 对应的就是我们的方法名字,所以我们在进行对应接口方法在XML中实现配置一定要确保自己的方法名填写正确!

准确来说到这里已经结束了对于增删改查大致方法的配置方法,然后应该考虑的是如何将这个mapper.xml与conf.xml绑定呢?

回到之前的conf.XML的标签,我们将我们这个mapper.xml插入其中就可以了,这个插入方法一共有3种方式

  1. _1.resource通过文件路径来查找_
  1. *2.class 通过类路径来查找(用于注解)*
  2. *3.package 忘记了。。。。。*

tip: 2和3如果仍旧使用XML的情况,需要确保接口类和XML文件在一个package下,且名字相同。

(不然找不到对应的sql方法,后面2种感觉不是很好的处理方式吧)

总而言之:以上的标准的绑定步骤就是 interface类 —> mapper.xml —>conf.xml

4.琐碎的知识

4.1 别名

因为在配置mapper时,我们无论是输入parametertype还是resultType我们都需要严格的输入正确的类路径,这是一件很麻烦的事,所以为了方便我们可以采用别名来进行简化输入’,别名的玩法有很对,下面是给包起别名,意思是在pojo包下的所有类在接下来调用是都不用完全按照类路径设置参数了,只需要取类名的首字母小写就可以了。或者像第二个把别名准确到类,但是二者不可以同时加载,这样会报错,当然采用包取别名也可以自定义名字,可以在包写的类上进行注解@Alias

  1. <typeAliases><package name="com.zjl.mybatis.pojo"/></typeAliases>
  2. <typeAliases><typeAlias type="com.zjl.mybatis.pojo.user" alias="u"></typeAlias></typeAliases>
  1. _图中所示就是user类用uuu来代替别名!!!_

开启日志的设置,以及驼峰命名

  1. <settings>
  2. <setting name="mapUnderscoreToCamelCase" value="true"/>
  3. <setting name="logImpl" value="STDOUT_LOGGING"/>
  4. </settings>

5.collection 和 association

如果数据库中出现了2张,3张甚至更多的table时,我们首先要考虑的是如何去编写pojo类。可以有一下猜想:

emp 对应着的 demp,我们不难联想到,多个员工对应着一个部门,这是多对一。相反。一个部门可以对应着多个员工,这就是一对多,而这种关系,在数据库是使用外键进行连接,我们可以通过联表查询,来找到对应的部门和员工。而在pojo类中,我们选择为pojo类添加类对象属性,如果说我们是员工类中要声明对应的部门,那就在员工的属性中添加一个Dept dept 进行实现,同理,如果说我们要表明一个部门的中所有员工信息的成员变量,那完全可以使用List emps 来实现声明,但是随之而来的问题就是如何进行数据库字段到属性的映射问题!

1.多对一的解决

我们在Mybatis中使用association进行处理,首先我们在声明查询结果处理类型时进行resultMap声明,先告诉系统我们要用自己的映射进行字段和属性的对应,然后对于字段和属性名相同的我们可以不做声明,(如果起了别名,应该声明对应关系)对于我们的自定义类成员变量,我们这样声明,如下

  1. <association property="teacher" javaType="mybatis.pojo.Teacher">
  2. <result column="tid" property="id"></result>
  3. <result column="tname" property="name"></result>
  4. </association>

解读:通过association来表示我们要对一个成员属性进行一个别的映射方式。依旧是先声明要对应的属性,然后javaType来表示我们要进行的类型赋值,在association中继续用result来处理查询结果,不过在这里就是对于我们刚刚声明的javaType的类型进行结果类型的声明,真正的结果集类型取决于select中的resultType!

总结:第一种方式其实是针对于我们的联表查询,我们的查询结果中已经筛选出了类中成员变量的属性,所以进行直接的赋值就可以了。

第二种方式:这种方式类似于子查询,在我们进行数据的查询时,先查一部分,然后再通过获得的一部分信息,去查询接下来的数据。

使用如下:

  1. <resultMap id="students" type="mybatis.pojo.Student">
  2. <association property="teacher" column="tid" javaType="mybatis.pojo.Teacher" select="getteacher"></association>
  3. </resultMap>
  4. <select id="getteacher" resultType="mybatis.pojo.Teacher">
  5. select * from teacher where id=#{tid}
  6. </select>

解读:首先还是进行一个resultMap的映射,但是我们并没有在这一次的查询中查到所以老师的信息,只是得到了一部分,然后我们要借助这一部分开启新的查询,所以中的属性的意义是,属性,对应的字段,子查询结果对应的类型,查询语句的id ,通过这样的操作,我们就可以根据主查询中的tid 进行一次子查询,然后得到一个对应的成员变量。

tips:这里要想明白的地方就是,我们在进行pojo和字段转换时其实也是循环的,可以想象成在进行一个for循环,在不停的读取我们的数据结果,然后每一行的数据都装进了我们的pojo中,pojo在放进List这种集合里。

一对多的解决

在一对多中也是非常简单的我们首先要把association换成collection.先看第一种方式

  1. <select id="getTeacherbyID" resultMap="teacher" >
  2. select t.id id ,t.name name ,s.id sid ,s.name sname ,s.tid stid
  3. from teacher t left join student s on t.id = s.tid where t.id = #{tid}
  4. </select>
  5. <resultMap id="teacher" type="mybatis.pojo.Teacher">
  6. <result property="id" column="id" ></result>
  7. <result property="name" column="name" ></result>
  8. <collection property="students" ofType="mybatis.pojo.Student">
  9. <result column="sid" property="id"></result>
  10. <result column="sname" property="name"></result>
  11. <result column="stid" property="tid"></result>
  12. </collection>
  13. </resultMap>

这里和association一个道理就是在读取数据的时候将students这个List属性的元素,进行for循环读取,我觉得他应该在下层进行了上层数据的比对,只有前面的字段都对应上得时候才会进行for循环,然后进行属性的赋值。这里要注意的是collection就是默认了我们这个属性是list 或者 set ,所以在中的属性ofType是在指示我们集合中的泛型是什么类型!

解读:首先要想明白一对多最终的查询结果是什么?在Java中我们的查询代码就是一个对应的pojo类对象,只不过是这个类对象中有一个list装着很多别的类对象。但是在数据库中我们的查询结果是什么样的?如图:

我们想要的是一行的id 和 name 和多行的 sid sname stid 这里是要注意的,所以我们可以这样,首先分开查询,先查出一部分信息,比如就是id ,然后通过id 进行一个子查询,这个子查询中返回类型是List 映射的类型是student 这样来实现一对多的关系映射。

  1. <select id="getTeacherbyId02" resultMap="teacher02">select * from teacher where id = #{tid}</select>
  2. <resultMap id="teacher02" type="mybatis.pojo.Teacher">
  3. <collection property="students" column="id" javaType="List" ofType="mybatis.pojo.Student" select="studentlist">
  4. </collection>
  5. </resultMap>
  6. <select id="studentlist" resultType="mybatis.pojo.Student">
  7. select * from student where tid = #{id}
  8. </select>

在这里我们也可以看出来,在多对一的时候声明了javaType进行结果类型的声明,一对多的时候自然就成为了List的结果集,然后声明List中的泛型属性是Student,完成这一子查询。

6.动态SQL

什么是动态sql,动态sql 无非就是为sql语句添加了逻辑判断。

主要的关键词有这几个 if where choose set foreach

if

标签进行逻辑判断,如果满足标签内的条件就会继续向下执行,每个条件之间用 and 连接,最后拼接好字符串之后进行查询

  1. <select id="queryBlog" parameterType="map" resultType="com.zjl.demo04.pojo.blog">
  2. select * from blog
  3. <where>
  4. <if test="title!=null">
  5. title = #{title}
  6. </if>
  7. <if test="author!=null">
  8. and author = #{author}
  9. </if>
  10. </where>
  11. </select>

解读:所有的关于动态sql的标签都嵌入到了sql语句内部。这里提一下的 作用,where这样写的好处在于,我们完全不需要判断标签体中是否会有内容,因为Mybatis 会帮助我们进行判断,如果说是没有任何条件进行匹配,那最后也会自动的为我们自动忽略where。那么if其实在这里是一样的道理,如果说我们第一个if 没有得到匹配,而第二个标签匹配,Mybatis就会为我们忽略掉 and tip: 但是不可以不写,因为在这里我们只有忽略,没有自动增加!!!

内部是用 test 来进行条件判断,如果说 “ ”中的条件成立,那么就会执行这条语句,而这个条件是来自于参数的,上面代码中对应的是map 中的key ,那么可以同理得知,如果是pojo对象,那就可以直接写上pojo的属性,而如果是单纯的几个基本类型参数可以通过@param(“名”)来对应到sql语句中。

choose

choose不难理解,其实就可以认为是我们switch结构 。可以暂且认为有以下的对应关系

choose when otherwise

switch case default

二者是的执行逻辑是基本一致的,但是也有一些地方有少许的不同;在choose中Mybatis会多个语句进行比较了,如果说当前条件是true,则匹配当前条件,然后直接进行数据的查询,就不会再看后面的数据了,但是如果当前的条件为false,那么就进行下一个when中信息的判断,如果说所有的when 中的判断条件都是false,那么就按照otherwise来执行最终的操作。下面是一个具体的例子(id多多少少不太对)

  1. <select id="queryBlogOr" resultType="com.zjl.demo04.pojo.blog">
  2. select * from blog <where>
  3. <choose>
  4. <when test="title!=null">
  5. title = #{title}
  6. </when>
  7. <when test="author!=null">
  8. author = #{author}
  9. </when>
  10. <otherwise>
  11. 1=1
  12. </otherwise>
  13. </choose>
  14. </where>
  15. </select>

set

set其实和where差不多,where 用来解决and 这个可能多余的关键字的问题,set 是用来解决 update 语句中的 “,”问题,因为我们是无法判断这个update中的条件到哪里结束的,如果执行到最后一句那自然是不用 ” ,“也能解决问题的,但是问题就是可能执行不到这句话,所以就会产生语法错误,所以这就是set 标签的作用。所以说为了规范化sql的查询,我们最好在每一句更新的赋值语句的最后写上一个 “ , “

  1. </select>
  2. <update id="update" parameterType="map">
  3. update blog <set>
  4. <if test="title!=null">
  5. title = #{title},
  6. </if>
  7. <if test="author!=null">
  8. author = #{author},
  9. </if>
  10. <if test="views!=null">
  11. views = #{views},
  12. </if>
  13. </set>
  14. <where>
  15. author = #{oldauthor}
  16. </where>

foreach

foreach在我目前来看,主要的应用场景在于in这种范围查询中,判断是否在一个集合中,foreach也是比较奇怪的使用构造,这里就说我目前的一种使用手段吧首先传入的参数是一个map 然后map里面有一个list ,在调用的时候,把map中的list中的值取出来就行了。

举个例子:

  1. <select id="forquery" parameterType="map" resultType="com.zjl.demo04.pojo.blog">
  2. select * from blog
  3. <where>
  4. <foreach collection="authors" item="author" open="author in (" separator="," close=")">
  5. #{author}
  6. </foreach>
  7. </where>
  8. </select>

解读:这里就是在说在where中调用我们的map中key值为authors的集合,然后取出其中的每一项进行循环,然后open separator close分别代表着我们集合中的每一项应该放在哪些位置,open代表这语句的开始,separator代表这每个集合元素的分割符号,close代表读完组后一个元素后,应当补齐的标点符号之类的信息。

sql

省略了,至于复用记住两个标签吧

  1. <include refid=""></include>
  2. <sql id=""></sql>