Mybatis入门
一.环境配置
1.引入依赖
- 引入mybatis的外部依赖
- 引入mysql的驱动依赖
2.配置mybatis-config.xml
-
mybatis-config.xml配置文件实例
<environments default="product"> <environment id="product"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> <environment id="test"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/testMapper.xml"/> </mappers>
-
配置文件中的
<properties resource="db.properties"></properties>
用于配置properties文件的信息 -
environments标签主要用于数据源的配置,可以配置多个数据源,通过default属性来指定当前项目运行过程中使用的是哪个数据源
- environment标签用于配置具体的独立的数据源,id属性用于给当前数据源定义一个名称,方便我们的项目指定
- environment标签中标签
- transactionManager用于配置事务管理,默认情况下使用的是JDBC事务管理
- dataSource配置具体数据源的链接信息,type属性用于指定是否使用连接池
-
mappers主要用于配置我们外部的映射配置文件,在主配置文件中需要引入加载映射配置文件
- mapper标签主要配置引入某一个具体的映射文件,resource进行路径方式的引入
3.配置mapper.xml
-
mapper.xml实例
<mapper namespace="org.mybatis.example.TestMapper"> <select id="findAll" resultType="org.mybatis.example.Test"> select * from test </select> </mapper>
-
mapper用于定义一个映射配置文件的根节点,namespace属性是用来配置命名空间主要进行session级别的缓存管理,命名空间默认情况下使用我们当前操作的实体类的全路径
4.配置实体类
- 创建与数据库表字段对应的实体类
二.动态SQL语句
1.if
-
动态 SQL 通常要做的事情是根据条件包含 where 子句的一部分。比如:
<select id="findActiveBlogWithTitleLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <if test="title != null"> AND title like #{title} </if> </select>
-
上述代码的title应传递的是对象,对象中的属性有title
2.choose(when,otherwise)
-
有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
-
还是上面的例子,但是这次变为提供了“title”就按“title”查找,提供了“author”就按“author”查找的情形,若两者都没有提供,就返回所有符合条件的 BLOG(实际情况可能是由管理员按一定策略选出 BLOG 列表,而不是返回大量无意义的随机结果)。
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> </select>
3.trim(where,set)
-
前面几个例子已经合宜地解决了一个臭名昭著的动态 SQL 问题。现在回到“if”示例,这次我们将“ACTIVE = 1”也设置成动态的条件,看看会发生什么。
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </select>
-
如果这些条件没有一个能匹配上会发生什么?最终这条 SQL 会变成这样:
SELECT * FROM BLOG WHERE
-
这会导致查询失败。如果仅仅第二个条件匹配又会怎样?这条 SQL 最终会是这样:
SELECT * FROM BLOG WHERE AND title like ‘someTitle’
-
这个查询也会失败。这个问题不能简单地用条件句式来解决,如果你也曾经*这样写过,那么你很可能从此以后都不会再写出这种语句了。MyBatis 有一个简单的处理,这在 90% 的情况下都会有用。而在不能使用的地方,你可以自定义处理方式来令其正常工作。一处简单的修改就能达到目的:
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG <where> <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </where> </select>
-
where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
-
prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。类似的用于动态更新语句的解决方案叫做 set。set 元素可以用于动态包含需要更新的列,而舍去其它的。比如:
<update id="updateAuthorIfNecessary"> update Author <set> <if test="username != null">username=#{username},</if> <if test="password != null">password=#{password},</if> <if test="email != null">email=#{email},</if> <if test="bio != null">bio=#{bio}</if> </set> where id=#{id} </update>
-
这里,set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号。若你对 set 元素等价的自定义 trim 元素的代码感兴趣,那这就是它的真面目:
<trim prefix="SET" suffixOverrides=","> ... </trim>
-
注意这里我们删去的是后缀值,同时添加了前缀值。
4.foreach
-
动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候。比如:
<select id="selectPostIn" resultType="domain.blog.Post"> SELECT * FROM POST P WHERE ID in <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach> </select>
-
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及在迭代结果之间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。
-
注意 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象传递给 foreach 作为集合参数。当使用可迭代对象或者数组时,index 是当前迭代的次数,item 的值是本次迭代获取的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
5.bind
-
bind
元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:<select id="selectBlogsLike" resultType="Blog"> <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" /> SELECT * FROM BLOG WHERE title LIKE #{pattern} </select>
6.动态SQL:sql片段—公用sql
-
定义sql片段,使用sql标签(id定义标识),如
<sql id="user_fields"> username,userpass,nickname,age,gender </sql>
-
引入sql片段,使用include标签(refid引入标识),如
<insert id="addUsers" useGenereateKeys="true" keyProperty="id"> insert into users(<include refid="user_fields"></include>) values(#{name},#{userpass},#{nickname},#{age},#{gender}) </insert> <!-- 等同于 insert into users(username,userpass,nickname,age,gender) values(#{name},#{userpass},#{nickname},#{age},#{gender}) -->
7.动态SQL:set配置
-
常规操作存在问题:如果一个值为null则插入的数据则为null
<update id="updateUser"> update users set username = #{name}, userpass = #{userpass}, nickname = #{nickname}, age = #{age}, gender = #{gender} where id = #{id} </update>
-
使用set配置
<update id="updateUser"> update users <set> <if test="name != null">username=#{name},</if> <if test="userpass != null">userpass=#{userpass},</if> <if test="nickname != null">nickname=#{nickname},</if> <if test="age != null">age=#{age}</if> <if test="gender != null">gender=#{gender}</if> </set> where id=#{id} </update>
三.实体中的属性与表字段不相同的解决方案
1.添加resultMap
-
实例代码如下
<!-- 自定义映射关系集合,主要包含对一些自定义操作的配置,如不一致的属性和字段名称 --> <resultMap id="forUsers" type="com.demo.entity.Users"> <!-- 配置实体类中的主键与数据库中的主键匹配使用id --> <!-- <id column="" property=""></id> --> <!-- result配置:column表示数据库中字段名,property表示实体类中的属性名 --> <result column="username" property="name"></result> </resultMap>
-
将resultType的返回类型改为resultMap并值为resultMap的id内容
-
注意:resultMap中只需要定义表与实体间不同名的内容,其他内容将自动映射
四.使用log4j打印日志记录
1.引入log4j依赖
2.添加log4j的properties配置文件(通过官网的log4j.properties文件获取)
3.使用log4j
- 创建对应的日志记录对象
private Logger log = Logger.getLogger(类名.class);
- 通过不同的级别进行日志的记录【级别:DEBUG/WARN/INFO/LOG】
log.info("查询到的id内容:"+id)
五.Mybatis相关特性
1.自动生成主键值
-
使用insert标签的useGenerateKeys="true"和keyProperty="id"定义主键,如
<insert id="addUsers" useGenereateKeys="true" keyProperty="id"> ... </insert>
六.基础进阶—多表关联入门
- 创建用户表和地址表,并设置关联(一个用户可以有多个地址)
- 在User实体中添加
List<Address>addresses
属性
1.一对一的映射<association>
- resultMap中绑定id字段
<id property="id" column="id"></id>
- association中定义一对多的类属性property,多的对象类型ofType,column传递到查询中的数据库字段名,select查询的sql标签id。
<association property="addresses" column="id" ofType="com.demo.entity.Address" select="getAddress"></association>
2.一对多的映射<collection>
- resultMap中绑定id字段
<id property="id" column="id"></id>
- collection中定义一对多的类属性property,多的对象类型ofType,column传递到查询中的数据库字段名,select查询的sql标签id。
<collection property="addresses" column="id" ofType="com.demo.entity.Address" select="getAddress"></collection>