MyBatis框架

MyBatis框架

MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架(DAO层)。

MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索

​ JDBC代码 : JDBC编程六步骤

​ 参数的手工设置: JDBC参数动态化 SQL语句中?的替换

​ 结果集的检索:ORM思想中对于ResultSet结果集的处理

思想

只关注持久层中最为核心的内容 --->  SQL语句
将所有的代码全部封装只留下配置文件 mapper.xml文件

interface UserDAO{
      List<User>  queryUser();
      void insert(User user);
}
          
mapper.xml  就相当于 JDBC中UserDAOImpl.java
          
<mapper  声明实现的是某一个具体的DAO接口 = UserDAO>
       <select  id="queryUser">
           select * from t_user;
       </select>
       <insert id="insert">
           insert into t_user values(对象中的数据);
       </insert>
</mapper>

一、第一个程序

1、环境搭建

1.1 导入jar包

1. mybatis 核心jar包                          mybatis-3.2.2.jar
2. 三方jar包  mybatis源码所依赖的其他java类      zip----> lib文件夹中
3. 数据库驱动jar                               ojdbc.jar

1.2 准备配置文件

 1、log4j.properties    日志
		将mybatis运行的流程日志全部进行打印   可选 : 打印到控制台 或者 写入文本中。
	位置: src 根目录下

	log4j日志如果使用在Web项目中,需要生效必须部署在服务器上。
	Web项目中使用Test测试是看不到运行日志的。

 2、mybatis-config.xml
		mybatis核心配置文件     
		2.1 对于数据库连接的访问参数配置
		2.2 对于mapper.xml文件的注册(声明)
	位置: 随意的   建议 src 根目录下

 3、Mapper.xml  只会实现一个DAO接口
		替换DAOImpl.java实现类的    和DAO接口的数量  一一对应关系
	位置: 随意

1.3 初始化配置

<configuration>
	<!-- JDBC数据连接的初始化配置 -->
	<environments default="oracle">
		<environment id="oracle">
			<!-- 使用传统的JDBC方式管理事务 -->
			<transactionManager type="JDBC" />
			<!-- POOLED MyBATIS中的连接池方式       可以进行后续的替换 c3p0 -->
			<dataSource type="POOLED">
				<property name="driver" value="oracle.jdbc.OracleDriver"></property>
				<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe">
                											</property>
				<property name="username" value="hr"></property>
				<property name="password" value="hr"></property>
			</dataSource>
		</environment>
	</environments>
	
	<!-- 声明注册项目中已经完成编码的mapper.xml文件的路径-->
	<mappers>
		<mapper resource="Mapper.xml文件的路径"></mapper>
	</mappers>
	
</configuration>
2、编码
实体类:
	User 属性 id 、 name 、password
	
接口:
public interface UserDAO {
	List<User> queryAll();
}

Mapper.xml

<!-- 
	namespace: 指定当前mapper.xml管理的接口 全限定名
	注意:一个mapper.xml只能管理一个接口
-->
<mapper namespace="com.baizhi.dao.UserDAO">
    
    <!--  id="方法名"   resultType=" 返回结果类型  集合中的泛型的全限定名" -->
	<select id="queryAll" resultType="com.baizhi.entity.User">
		select * from t_user;
	</select>
	
</mapper>

注意: 完成mapper.xml的开发之后还需要去mybatis-config.xml中进行注册

mybatis-config.xml文件

<!-- 声明注册项目中已经完成编码的mapper.xml文件的路径-->
<mappers>
    <mapper resource="com/baizhi/mapper/UserDAOMapper.xml"></mapper>
</mappers>
3、测试
@Test
public void testQueryAll()throws Exception{
    //如何获取UserDAO的实现类结果呢?  UserDAO userDAO = new UserDAOImpl();
    /* 1.   Resources  用来读取mybatis核心配置文件
	 * 2.   SqlSessionFactory   SqlSession工厂 (连接工厂)
     * 3.   SqlSeesion对象        为MyBATIS技术中的连接对象    相当于JDBC中的connection
	 *      SqlSeesion.getMapper()  ----> 获取DAO的实现类对象
	 */
    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserDAO userDAO = sqlSession.getMapper(UserDAO.class);
    List<User> queryAll = userDAO.queryAll();
    for (User user : queryAll) {
        System.out.println(user);
    }
    is.close();
    sqlSession.close();
}
DML操作


接口方法:void deleteUser(int id);


Mapper.mxl配置文件:
    <!-- 方法中参数的类型  parameterType="int" 可以省略  针对八种基本类型以及String的时候-->
    <delete id="deleteUser" >
            delete from t_user where id = #{id}
    </delete>


Test测试类:
	//读取mybatis核心配置文件
	InputStream resourceAsStream = 
        		Resources.getResourceAsStream("mybatis-config.xml");
	//获取工厂   sqlSession的工厂
	SqlSessionFactory sessionFactory = 
        		new SqlSessionFactoryBuilder().build(resourceAsStream);
	//获取sqlsession对象
	SqlSession sqlSession = sessionFactory.openSession();
	//UserDAO userDAO = 
	UserDAO userDAO = sqlSession.getMapper(UserDAO.class);
	userDAO.deleteUser(1);
	//默认事务选择rollback回滚  必须手动进行提交	
    sqlSession.commit();
    resourceAsStream.close();
    sqlSession.close();

二、参数传递

1、如果方法中只有一个参数

void deleteUser(int id);

#{取值可以随便写} :#{a} 标准写法: #{0} 建议和参数名称对应:#{id}

2、如果方法中有多个参数

2.1 使用原始的数组 默认

User queryUser(String name ,String password);

#{按照数组下标} mybatis会将参数列表封装到数组中

name = #{0} and password = #{1}

2.2使用参数绑定 @Param注解

User queryUser(@Param(“name”)String name,@Param(“p”)String password);

select * from t_user where name = #{name} and password = #{p}

3、使用Map集合
// Map  集合    key=value    name=123     password=123
User queryUserMap(Map<String,Object> maps);

xml:   #{map集合中的key}
<select id="queryUserMap" resultType="com.baizhi.entity.User">
		select * from t_user where name = #{name} and password = #{password}
</select>
	
使用:
HashMap<String, Object> hashMap = new HashMap<String,Object>();
hashMap.put("name", "123");
hashMap.put("password", "123");
User queryUser = userDAO.queryUserMap(hashMap);

4、用户自定义对象
<!-- 方法中参数的类型  parameterType="全限定名" 如果是用户自定义对象一定需要添加 -->
<insert id="insertUser" parameterType="com.baizhi.entity.User">
    <!-- id name password  为用户自定义对象的属性 -->
    insert into t_user values(#{id},#{name},#{password})
</insert>

注意: 查询操作中 如果接口的方法返回值是一个对象 则SQL语句的查询结果必须也是一个。

org.apache.ibatis.exceptions.TooManyResultsException:

​ Expected one result (or null) to be returned by selectOne(), but found: 2

5、使用序列生成ID

建议书写格式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G3XVJVRo-1594885695797)(E:\JavaWeb\Mybatis\笔记\1.png)]

<insert id="insertUser" parameterType="com.baizhi.entity.User">
    insert into t_user values(user_seq.nextval,#{name},#{password})
</insert>

三、MyBatisUtil的封装

封装思想完全遵循 JDBCUtil

对于冗余代码的封装、执行效率(static{} 静态代码块)、线程绑定(ThreadLocal)

package com.baizhi.util;

import java.io.IOException;
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 MyBatisUtil {
	private static SqlSessionFactory sessionFactory;
	private static ThreadLocal<SqlSession>  tl = new ThreadLocal<SqlSession>();
	static{
		try {		
			InputStream resourceAsStream = 
                Resources.getResourceAsStream("mybatis-config.xml");
			//获取工厂   sqlSession的工厂
			sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
			resourceAsStream.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	//获取SqlSeesion 连接
	public static SqlSession getSqlSeesion() throws IOException{	
		SqlSession sqlSession = tl.get();
		if(sqlSession==null){
			//获取sqlsession对象
			sqlSession = sessionFactory.openSession();
			tl.set(sqlSession);
		}
		return sqlSession;
	}
	
	//关闭资源    需要在关闭资源之前 先进行线程的解除绑定 
	public static void close(){
		try {
			SqlSession sqlSession = getSqlSeesion();
			//线程接触绑定
			tl.remove();
			sqlSession.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
		
	public static void commit(){
		try {
			SqlSession sqlSession = getSqlSeesion();
			sqlSession.commit();
			//调用本类中的关闭方法
			close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
		
	public static void rollback(){
		try {
			SqlSession sqlSession = getSqlSeesion();
			sqlSession.rollback();
			//调用本类中的关闭方法
			close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

四、配置文件中的一些细节

1、实体类(entity)别名
User queryUser();
方法的返回值类型 : resultType="com.baizhi.entity.User"

void insertUser(User user);
方法的参数表类型 : parameterType="com.baizhi.entity.User"


<typeAliases>
    <!-- type 实体类的权限定名称    alias 别名  实体类的类名    -->
    <typeAlias type="com.baizhi.entity.User" alias="User"/>
</typeAliases>

<!-- resultType / parameterType = "User"-->
2、配置文件的参数化

将mybatis-config.xml中 跟数据库相关的配置参数书写在另一个配置文件中。

简化后续操作的复杂性

<!-- 读取jdbc相关配置信息的 文件    进行数据的填充需要使用 ${key} -->
	<properties resource="jdbc.properties"></properties>


<!-- 具体的参数配置已经转移到另外一个更小的配置文件中  jdbc.properties -->
    <property name="driver" value="${driver}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>

五、resultMap 结果映射

ORM 对象关系映射 数据库中表的列名 ----> java中对象的属性名称

​ 如果表中的列名和实体类的属性名不对应呢?

Mapper.xml 中书写

    <!-- type="需要进行属性和列名对应的实体类" -->
    <resultMap type="User" id="UserResultMap">
        <!-- 主键列 使用 id标签  剩下的列使用  result标签 -->
        <!-- property="实体类属性" column="表的列名" -->
        <id property="id" column="id"/>
        <result property="username" column="name"/>
        <result property="password" column="password"/>
    </resultMap>


    <select id="queryAll" resultMap="UserResultMap">
        select * from t_user 
    </select>

六、表中的关联关系

1、 一对一关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6rH30fZK-1594885695803)(E:\JavaWeb\Mybatis\笔记\一对一.png)]

查询Pseron对象以及其身份信息 — 来源于两张表的结果集合

书写 ResultMap 手动完成结果映射

<resultMap type="Person" id="PersonResultMap">
    <id property="p_id" column="p_id"/>
    <result property="p_name" column="p_name"/>
    <result property="birthday" column="birthday"/>
    <result property="sex" column="sex"/>
    <result property="id" column="id"/>
    <!-- association  Person实体类中有个一属性是用户自定义属性 
		切在数据查询的时候来源于另外一张表  -->
    <!-- property="类中的属性名称" javaType="属性的类型"  -->
    <association property="idCart" javaType="IDCart">
        <id property="id" column="id"/>
        <result property="address" column="address"/>
        <result property="name" column="name"/>
    </association>
</resultMap>
	
<select id="queryAll" resultMap="PersonResultMap">
    select * from Person p
    inner join IDCart i
    on p.id = i.id
</select>

Struts+MyBATIS整合 问题 ----- jar包冲突 commons-logging-1.1.3.jar/ javassist-3.17.1.GA.jar

建议 使用版本较高的jar包

2、一对多

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OKy1OSo2-1594885695806)(E:\JavaWeb\Mybatis\笔记\一对多.png)]

<resultMap type="Cla" id="ClaResultMap">
    <id property="cla_id" column="cla_id"/>
    <result property="address" column="address"/>
    <!-- 实体类属性是一个完整的集合对象 -->
     <!-- property="实体类中属性的名称" ofType="集合中的泛型" -->
    <collection property="stus" ofType="Stu">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <result property="cla_id" column="cla_id"/>
    </collection>
</resultMap>
3、多对多

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-28RI0sEZ-1594885695813)(E:\JavaWeb\Mybatis\笔记\多对多.png)]

需要引入第三张表去进行关联关系的拆分

关系表不需要主键存在 — 两个外键可以视为 联合主键

实体类设计 每个实体类其中的一个属性是另一个是实体类的集合

七、动态SQL

1、SQL片段
<sql id="T_USER_SELECT">
    id,name,password
</sql>

<select id="queryAll" resultType="User" >
    select <include refid="T_USER_SELECT"/>  
    from t_user
</select>
2、where 判断
<select id="queryUser" parameterType="User" resultType="User">
    select * from t_user
    <where>
        <if test="id!=null">
            id=#{id}
        </if>
        <if test="name!=null">
            and name=#{name}
        </if>
        <if test="password!=null">
            and password=#{password}
        </if>
    </where>
</select>

1、会根据实体类中具体的属性个数来生成对应的查询条件判断
2、八种基本类型需要进行区分 int 默认值是0   Integer 默认值才是 null
<select id="queryUser" parameterType="User" resultType="User">
    select * from t_user
    <!-- prefix="where" 标识 trim 替换where 标签   
 			prefixOverrides="and"  忽略第一个and 关键字 -->
    <trim prefix="where" prefixOverrides="and">
        <if test="id!=0">
            id=#{id}
        </if>
        <if test="name!=null">
            and name=#{name}
        </if>
        <if test="password!=null">
            and password=#{password}
        </if>
    </trim>
</select>
3、set 修改

如果列数据为null 则不进行修改,减少每一次修改对正行数据进行更新的问题。

<update id="updateUser" parameterType="User">
    update t_user  
    <set>
        <if test="name!=null">
            name=#{name},
        </if>
        <if test="password!=null">
            password=#{password}
        </if>
    </set>
    where id=#{id}
</update>
<update id="updateUser" parameterType="User">
    update t_user  
    <!--   suffixOverrides=","  和 where中的不一样!!!!!!   -->
    <trim prefix="set" suffixOverrides=",">
        <if test="name!=null">
            name=#{name},
        </if>
        <if test="password!=null">
            password=#{password}
        </if> 
    </trim>
    where id=#{id}
</update>
4、foreach
<delete id="delete">
    delete from t_user 
    where id in  
    <!-- 集合 ids   open( #{id} , #{id},#{id}   )close-->
    <foreach collection="list" open="("  item="id"  separator="," close=")">
        #{id}
    </foreach>
</delete>

collection = "集合的类型"
item="当前的遍历对象"    #{item属性值}

八、缓存

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BOMCE6HM-1594885695817)(E:\JavaWeb\Mybatis\笔记\缓存.png)]

配置
1. 声明缓存的使用
	开启二级缓存    mybatis-config.xml中
	<!-- 开启MyBatis二级缓存 -->
	<settings>
		<setting name="cacheEnabled" value="true"/>
	</settings>

2. 使用标记缓存   Mapper.xml  文件中
	<cache/>

3. 长时间为进行二次查询的数据会 唤回数据库(销毁)
	所有的实体类需要实现对象序列化

注意:

1、 如果发生了数据的修改(DML操作 ----> commit)
	MyBatis会自动清空缓存区中的数据 

2、 缓存越多越好吗?
	时间 成本

3、 查询操作一定要关闭连接 sqlSession
作业字段

用户表 用来登录注册 账号/密码/邮箱

省份表 ID 省份 标签

景点表 ID 景点 印象图 旺季时间 旺季门票 淡季门票 简介 外键 省份的ID

 添加景点: 选择其对应的省份   省份信息需要动态的从数据库中获取
 景点个数: 需要从景点表中动态的获取
1. 声明缓存的使用
	开启二级缓存    mybatis-config.xml中
	<!-- 开启MyBatis二级缓存 -->
	<settings>
		<setting name="cacheEnabled" value="true"/>
	</settings>

2. 使用标记缓存   Mapper.xml  文件中
	<cache/>

3. 长时间为进行二次查询的数据会 唤回数据库(销毁)
	所有的实体类需要实现对象序列化

注意:

1、 如果发生了数据的修改(DML操作 ----> commit)
	MyBatis会自动清空缓存区中的数据 

2、 缓存越多越好吗?
	时间 成本

3、 查询操作一定要关闭连接 sqlSession
作业字段

用户表 用来登录注册 账号/密码/邮箱

省份表 ID 省份 标签

景点表 ID 景点 印象图 旺季时间 旺季门票 淡季门票 简介 外键 省份的ID

 添加景点: 选择其对应的省份   省份信息需要动态的从数据库中获取
 景点个数: 需要从景点表中动态的获取
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值