Mybatis

1.概述

​ Mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc ,使开发者只需要关注 sql 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。

  • Mybatis 通过 xml 或注解的方式将要执行的各种 statement 配置起来,并通过java对象和 statement 中sql的动态参数进行映射生成最终执行的 sql 语句,最后由 Mybatis 框架执行 sql 并将结果映射为 java 对象并返回。

  • 采用ORM 思想解决了实体和数据库映射的问题,对 jdbc 进行了封装,屏蔽了jdbc api底层访问细节,使我们不用与 jdbc api打交道,就可以完成对数据库的持久化操作。

持久层技术解决方案

  • JDBC技术:

    • Connection
    • PreparedStatement
    • ResultSet
  • Spring的 JdbcTemplate:

    • Spring 中对 jdbc 的简单封装
  • Apache 的 DBUtils:

    • 它和 Spring 的 JdbcTemplate 很像,也是对 Jdbc 的简单封装

以上这些都不是框架,JDBC是规范,Spring 的 JdbcTemplate 和 Apache 的 DBUtils 都只是工具类

ORM

Object Relational Mappging 对象关系映射

简单的说:

  • 就是把数据库表和实体类及实体类的属性对应起来

  • 让我们可以操作实体类就实现操作数据库表。

2.入门

2.1.环境搭建

  1. 创建 maven 工程并导入坐标

  2. 创建实体类和 dao 的接口

  3. 创建 Mybatis 的主配置文件 :SqlMapConifg.xml

  4. 创建映射配置文件:IUserDao.xml

    • 这里可以使用@Select注解,并指定 sql ,便可以去掉该配置文件(使用注解就得去掉)
    • 同时需要在SqlMapConfig.xml中的 mapper 配置时,使用 class 属性指定dao接口的全限定类名。
    public interface IUserDao {
          
     	@Select("select * from user") 
        List<User> findAll(); 
    }
    
    <!-- 告知mybatis映射配置的位置 --> 
    <mappers> 
        <mapper class="com.leyou.dao.IUserDao"/> 
    </mappers>
    

Mapper 文件

以下内容为 IUserDao.xml

  1. 在 Mybatis 中它把持久层的操作接口名称和映射文件也叫做:Mapper。所以:IUserDao ,也可以写成IUserMapper
  2. Mybatis 的映射配置文件位置必须和 dao 接口的包结构相同
  3. 映射配置文件的 mapper 标签 namespace 属性的取值必须是 dao 接口的全限定类名
  4. 映射配置文件的操作配置(select),id 属性的取值必须是 dao 接口的方法名
  5. 当我们遵从以上几点之后,我们在开发中就无须再写 dao 的实现类
<mapper namespace="com.leyou.dao.IUserDao"> 
    <!-- 配置查询所有操作 --> 
    <select id="findAll" resultType="com.leyou.domain.User"> 
   	 	select * from user </select>
</mapper>

2.2.全局配置文件

<?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">
<!-- mybatis的主配置文件 -->
<configuration>
    <!-- 配置环境 -->
    <environments default="mysql">
        <!-- 配置mysql的环境-->
        <environment id="mysql">
            <!-- 配置事务的类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置数据源(连接池) -->
            <dataSource type="POOLED">
                <!-- 配置连接数据库的4个基本信息 -->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件
        如果是用注解来配置的话,此处应该使用 class属性指定被注解的dao全限定类名
    -->
   <!-- 使用xml的方式
		<mappers> <mapper resource="com/leyou/dao/IUserDao.xml"/> </mappers 
	-->
    <mappers>
        <mapper class="com.leyou.dao.IUserDao"/>
    </mappers>
</configuration>

2.3.测试类

程序编写的思路

  1. 读取配置文件 加载方式区别解惑
  2. 创建 SqlSessionFactory 工厂
  3. 创建 SqlSession
  4. 创建 Dao接口的代理对象
  5. 执行 Dao 中的方法
  6. 释放资源
 /**
     * 入门案例
     * @param args
     */
    public static void main(String[] args)throws Exception {
   
        //1.读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        //3.使用工厂生产SqlSession对象
        SqlSession session = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        IUserDao userDao = session.getMapper(IUserDao.class);
        //5.使用代理对象执行方法
        List<User> users = userDao.findAll();
        for(User user : users){
   
            System.out.println(user);
        }
        //6.释放资源
        session.close();
        in.close();
    }
}

2.4.流程分析

在这里插入图片描述

2.5. SqlSession

sqlSession 深入

SqlSession 的语句执行方法

  • Object selectOne(String statement, Object parameter)
  • List selectList(String statement, Object parameter)
  • int insert(String statement, Object parameter)
  • int update(String statement, Object parameter)
  • int delete(String statement, Object parameter)

注意

  • 一般情况下(方法重名了),这里的 statement 不能只传递方法名(如 findAll),需要前面带上 namespace,即 namespace.方法

selectOne 和selectList 的不同仅仅是 selectOne 必须返回一个对象。如果多余一个,或者没有返回(或返回了null),那么就会抛出异常。如果你不知道需要多少对象,使用 selectList 。如果你想检查一个对象是否存在,那么最好返回统计数(0或1)。

因为并不是所有语句都需要参数,这些方法都是有不同重载版本的,它们可以不需要参数对象。

2.6.作用域分析

参考

SqlSessionFactoryBuilder

​ 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 实例的最佳范围是**方法范围(**也就是局部方法变量)。你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但是最好还是不要让其一直存在以保证所有的 XML 解析资源开放给更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏味道(bad smell)”。因此  SqlSessionFactory 的最佳范围是应用范围。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的范围是请求或方法范围。绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。也绝不能将 SqlSession 实例的引用放在任何类型的管理范围中,比如 Serlvet 架构中的HttpSession。如果你现在正在使用一种 Web 框架,要考虑 SqlSession 放在一个和 HTTP 请求对象相似的范围中。换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很重要的,你应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。

使用 MyBatis-Spring 之后,你不再需要直接使用 SqlSessionFactory,因为你的 bean 可以被注入一个线程安全的 SqlSession,它能基于 Spring 的事务配置来自动提交、回滚、关闭 session。官方文档

3. CRUD

3.1.基于xml

3.1.1. CRUD

CRUD

  • insert
  • delete
  • update
  • select

模糊查询

  • 方式一:select * from user where username like #{username}
    • 没有加入%来作为模糊查询的条件,{username}也只是一个占位符,所以 sql 语句显示为
  • 方式二:select * from user where username like '%${value}%'
    • 如果用模糊查询的这种写法,那么${value}的写法就是固定的,不能写成其它名字。

#{}${}的区别

  • #{}表示一个占位符号 通过#{}可以实现preparedStatement向占位符中设置值,自动进行 java 类型和 jdbc类型转换,#{}可以有效防止 sql 注入
    • #{}可以接收简单类型值或 pojo 属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
  • ${}表示拼接 sql 串 通过${}可以将parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换
    • ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是 value。

3.1.2.参数细节

以查询为例

 <!-- 根据id查询用户 -->
    <select id="findById" parameterType="INT" resultMap="userMap">
        select * from user where id = #{uid}
    </select>
  • id="findAll":sql 语句所要应用 在 Dao接口的 方法名
  • parameterType="INT"参数类型。传入一个类的对象,就写类的全名称(注册可使用别名)。大小写不敏感。(常使用包装类)
  • resultType="int":可以指定结果集的类型,它支持基本类型和实体类类型,规则同parameterType
    • 实体类中的属性名称 必须和查询语句中的列名保持一致,否则无法实现封装。
    • Mysql 在windows系统中不区分大小写
    • Linux 中就需要小心使用了
  • sql 语句中使用#{}字符来表示占位符,它用的是 ognl 表达式
  • resultMap="userMap"结果类型,建立查询的列名和实体类的属性名称不一致时建立对应关系
    • 在 select 标签中使用 resultMap 属性指定引用即可,这里便是一处引用。
    • 后面会详细介绍

获取新增用户 id 的返回值

​ 新增用户后,同时还要返回当前新增用户的id值,因为id是由数据库的自动增长来实现的,所以就相当于我们要在新增后将自动增长 auto_increment的值返回。

 <!-- 保存用户 -->
    <insert id="saveUser" parameterType="user">
        <!-- 配置插入操作后,获取插入数据的id -->
        <selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER">
            select last_insert_id();
        </selectKey>
        insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});
    </insert>
  • order:定义获取 id 的时间
    • BEFORE:插入前
    • AFTER:插入后

ognl

它是 apache 提供的一种表达式语言,全称是:Object Graphic Navigation Language 对象图导航语言

  • 语法格式就是使用 #{对象.对象}的方式
    • #{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用getUsername()方法把值取出来。
    • 但是我们在parameterType属性上指定了实体类名称,所以可以省略user.而直接写username

3.1.3.类与表名不一致

方式一:使用别名

 <!-- 配置查询所有操作 --> 
<select id="findAll" resultType="com.leyou.domain.User"> 
    select id as userId,username as userName,birthday as userBirthday, sex as userSex,address as userAddress from user 
</select>

该方法效率最高,但是如果查询很多,开发起来不是很方便

方式二:resultMap

resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。

  • 在 select 标签中使用 resultMap 属性指定引用即可。
  • 同时 resultMap 可以实现将查询结果映射为复杂类型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。
<!-- 建立User实体和数据库表的对应关系
type属性:指定实体类的全限定类名 id属性:给定一个唯一标识,是给查询select标签引用用的。
--> 
<resultMap type="com.leyou.domain.User" id="userMap"> 
    <id column="id" property="userId"/> 
    <result column="username" property="userName"/> 
    <result column="sex" property="userSex"/> 
</resultMap>
  • id 标签:用于指定主键字段
  • result 标签:用于指定非主键字段
  • column 属性:用于指定数据库列名
  • property 属性:用于指定实体类属性名称

3.1.4.参考 Mapper 配置文件

Mapper 配置文件参考

<?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.leyou.dao.IUserDao">

    <!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
    <resultMap id="userMap" type="com.leyou.domain.User">
        <!-- 主键字段的对应 -->
        <id property="userId" column="id"></id>
        <!--非主键字段的对应-->
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值