Mybatis全解

Posted Recently 祝祝

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis全解相关的知识,希望对你有一定的参考价值。

什么是Mybatis:

mybati是一个半自动化轻量级持久性框架,支持自定义SQL、存储过程和高级映射。MyBatis消除了几乎所有的JDBC代码以及手动设置参数和检索结果。MyBatis可以使用简单的XML或注释进行配置,并将原语、接口和Java POJO(普通的旧Java对象)映射到数据库记录

什么是半自动化轻量级持久性框架:

**半自动化:**手动实现SQL

**轻量级:**运行效率比较高(事实测试)

**持久化:**数据持久化(Mybatis,hibernate,jpa)

Mybatis底层原理—》动态代理:

通过动态代理产生会话,运行mybatis相关配置

package com.uplooking.utils;

import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MybatisUtils {
	// 单例
	private static SqlSessionFactory factory = null;

	static {
		try {
			// 接在配置文件
			InputStream inputStream = Resources.getResourceAsStream("mybatis.cfg.xml");
			factory = new SqlSessionFactoryBuilder().build(inputStream);
			System.out.println(factory);
			inputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static SqlSession getSqlSession() {
		return factory.openSession(false);
	}

	public static void closeSqlSession(SqlSession sqlSession) {
		if (sqlSession != null) {
			sqlSession.close();
		}
	}
}

关键语句:
先是用Resources.getResourceAsStream读取配置文件返回一个字节流类型的数,
在创建一个 SqlSessionFactory对象,通过new SqlSessionFactoryBuilder().build(inputStream)导入刚刚读取到的字节流获得
在通过得到的会话工厂开启会话,默认为FALSE,factory.openSession(false);
之后就可以使用了,只需要在执行类里通过建造代理类,使用代理类调用getMapper方法,传入对象就能产生一个代理了

Mybatis使用:

只需要在java项目下面建立一个lib文件夹将Mybatisjar包导入即可使用,如果需要连接数据库还需要导入JDBC相关的包
这是我导入的包:

Mybatis基本配置:

mybatis核心配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" >

<configuration>
<settings>
	<!--mybatis SQL脚本跟踪-->
	<setting name="logImpl" value="STDOUT_LOGGING" />
	<!--启动二级缓存 默认为false-->
	<setting name="cacheEnabled" value="true" />
</settings>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC"></transactionManager>
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver"/>
				<property name="url" value="jdbc:mysql://localhost:3306/mytest"/>
				<property name="username" value="root"/>
				<property name="password" value="root"/>
			</dataSource>
		</environment>
	</environments>
	<mappers>
	<mapper resource="mappers/DeptDO.xml"/>
	<mapper resource="mappers/EmpDO.xml"/>
	</mappers>
</configuration>

相关对象的配置文件:

接口方法返回一对多,就是链表查询,返回一个链表类型:

<mapper namespace="绑定的接口全类名">
	<resultMap type="Bean对象全类名" id="规则名">
		<result column="id" property="id"/>
		<result column="dept_name" property="dname"/>
		...
		<collection property="List属性名" ofType="List里的类的全类名">
			<id column="数据库主键名" property="List里的类的属性名"/>
			<result column="数据库列名" property="List里的类的属性名"/>
		</collection>
	</resultMap>
</mapper>

重点句:<collection property="List属性名" ofType="List里的类的全类名">

接口方法返回值多对一 ,返回值为单个类型:

<mapper namespace="绑定的接口全类名">
	<resultMap type="Bean对象全类名" id="Bean对象全类名">
		<id column="id" property="id"/>
		<result column="last_name" property="lastName"/>
		...
		<association property="自定义类属性名" select="接口全类名.方法名(即其它sql配置文件的语句)"
					 column="列名(即传入查到的哪一列作为其它sql语句需要传入的参数值)">
		</association>
	</resultMap>
</mapper>

重点语句:

<association property="自定义类属性名" select="接口全类名.方法名(即其它sql配置文件的语句)"
					 column="列名(即传入查到的哪一列作为其它sql语句需要传入的参数值)">
		</association>

只是改变查询列的属性名与数据库属性名不同,只需要更改映射表返回值类型变为自定义类型即可:

<mapper namespace="绑定的接口全类名">
	<resultMap type="Bean对象全类名" id="规则名">
		<id column="数据库下的主键名" property="Bean对象的属性名"/>
		<result column="数据库下的列名" property="Bean对象的属性名"/>
	</resultMap>
	<select id="接口方法" resultMap="规则名">
		.....
	</select>
</mapper>


批量插入:
接口:

配置文件:

 <insert  id="insertBatch">
 insert into deptbl(deptno,dname,loc) values
 <foreach collection="items" item="item" separator=",">
 (#{item.deptno},#{item.dname},#{item.loc})
 </foreach>
 </insert>

重点语句:

 <foreach collection="items" item="item" separator=",">

测试:

批量删除:
配置文件:

 <delete id="deleteBatch">
 delete from deptbl where deptno in 
 <foreach collection="ids" open="(" separator="," close=")" item="id">
 ${id}
 </foreach>
 </delete>

重点代码:

<foreach collection="ids" open="(" separator="," close=")" item="id">

测试:

条件查询:
分页:

  <!-- 分页 -->
  <select id="find5" resultType="com.uplooking.pojo.EmpVO">
  select empno,ename,sal,deptno FROM emp 
   <if test="cond.sal!=null ">
  order by ${cond.sal} 
  </if>
  <if test="cond.order!=null and cond.order!=''">
   ${cond.order}
  </if> 
  limit	#{limit},#{size}
  </select>

排序:

  <!-- 排序查询 -->
  <select id="find4" resultType="com.uplooking.pojo.EmpVO" >
  SELECT empno,ename,sal,deptno FROM emp 
  <if test="cond.sal!=null ">
  order by ${cond.sal} 
  </if>
  <if test="cond.order!=null and cond.order!=''">
   ${cond.order}
</if> 

模糊查询:

  <select id="find3" resultType="com.uplooking.pojo.EmpVO" >
  SELECT empno,ename,sal,deptno FROM emp 
  <where>
  <if test="cond.name!=null and cond.name!=''">
   ename like concat('%',#{cond.name},'%')
  </if>
  <if test="cond.job=null and cond.job!=''">
  AND JOB=#{cond.job}  
  </if>
  <if test="cond.sal!=null and cond.sal!=''">
  AND sal &lt; =#{cond.sal}   
  </if>
  </where>
  </select>

重点语句:

ename like concat('%',#{cond.name},'%')

细节-> 处理自增列

selectKey 会将 SELECT LAST_INSERT_ID()的结果放入到传入的model的主键里面,
接口:

	int insert(@Param("item")MybtisVO item);

<insert id="insert">
INSERT INTO mybtis(sname) VALUES (#{item.sname})
 <!--selectKey  会将 SELECT LAST_INSERT_ID()的结果放入到传入的model的主键里面,
            keyProperty 对应的model中的主键的属性名,这里是 user 中的id,因为它跟数据库的主键对应
            order AFTER 表示 SELECT LAST_INSERT_ID() 在insert执行之后执行,多用与自增主键,
                  BEFORE 表示 SELECT LAST_INSERT_ID() 在insert执行之前执行,这样的话就拿不到主键了,
                        这种适合那种主键不是自增的类型
            resultType 主键类型 -->

<selectKey keyProperty="MID" order="AFTER" resultType="int">
select LAST_INSERT_ID()
</selectKey>
</insert>

重点代码:

<selectKey keyProperty="MID" order="AFTER" resultType="int">
select LAST_INSERT_ID()
</selectKey>

若SQL语句都相同可以提取出来作为一个方法:

<sql id="sqlBase">
		SELECT empno,ename,job,hiredate,sal FROM emp 
	</sql>

只需要在其他操作的xml语句后添加就可以引用了:

<select id="find" resultType="com.uplooking.pojo.EmpVO">
		<include refid="sqlBase"/> 
		<trim prefix="WHERE" prefixOverrides="AND">
			<if test="job!=null and job!=''">
				AND job = #{job} <!-- 'SALESMAN' -->
			</if>
			<if test="sal!=null">
				AND sal &lt;= #{sal} 
			</if>
		</trim>
	</select>

引用自定义SQL语句:

<include refid="sqlBase"/> 

自定义SQL:

当sql返回条件已经在文件里不存在时,此时需要自定义一个pojo类以用于接收返回值
映射配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.uplooking.dao.EmpDO">
<cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>
<resultMap type="com.uplooking.pojo.GroupVO"  id ="GroupMap">
<result  column="number"   property="tc"/>
<result  column="name"   property="job"/>
</resultMap>
<select id="count" resultType="int">
${sql}
</select>
<select id="count1" resultType="int">
select count(empno) from emp 
</select>
<select id="countGroup" resultMap="GroupMap">
${sql}
</select>
<select id="countGroup1" resultMap="GroupMap">
select count(job) tc,job from emp group by job
</select>
</mapper>

自定义返回值实现类:

public class GroupVO {
	private int number;
	private String name;

实现:

	SqlSession session =MybatisUtils.getSqlSession();
		EmpDO empDO =session.getMapper(EmpDO.class);
		String sql= "select count(empno) from emp";
		System.out.println(empDO.count(sql));
		System.out.println(empDO.count1());
		System.out.println("----------------------------");
		String sql1 ="select count(job ) tc ,job from emp group by job";
		System.out.println(empDO.countGroup(sql1));
		System.out.println(empDO.countGroup1());

end》》》
静下心来分析,代码就会越看越有趣

以上是关于Mybatis全解的主要内容,如果未能解决你的问题,请参考以下文章

mybatis学习(39):动态sql片段

SSM-MyBatis-05:Mybatis中别名,sql片段和模糊查询加getMapper

mybatis动态sql片段与分页,排序,传参的使用

MyBatis动态SQL标签用法

MYBATIS05_ifwherechoosewhentrimsetforEach标签sql片段

XDCTF2015代码审计全解