MyBatis

概念

  1. MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。
  2. MyBatis 消除了几乎所有的 JDBC 代码和参数手工的设置以及结果集的检索。
  3. 中文官网: https://mybatis.net.cn/

优点

  1. 简化JDBC的开发,且支持各种Sql的代码
  2. 能够更好的完成ORM(对象关系映射)
  3. 提供缓存的技术,提高了程序查询的效率
  4. 减少了和数据库的交互次数,相同的数据不会在次访问数据库了(缓存)
  5. 自动完成ORM的映射(ORM:类和表的关系、属性和字段名的关系 不同类型系统的数据之间的转换)

ORM概念

是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换,在MyBatis里是对:

  • 类和表之间数据互相对应转换的关系(类对应表)
  • 属性和字段名类型数据的互相对应转换的关系(字段名对应属性名)

运行原理

在这里插入图片描述

缓存

MyBatis中默认事务是关闭的,如果对数据库进行了修改,则需要主动提交事务,否则数据库无法保存缓存的数据

  1. MyBatis中当第一次查询数据时,缓存中肯定没有,它直接会去查询数据库,然后还会把数据存入缓存
  2. 第二次查询相同的数据时,先去查缓存,有就直接用,没有再去查数据库
  3. MyBatis中默认是开启缓存的

使用缓存的前提是:

  1. 必须基于相同的数据
  2. 同一个SqlSession对象

MyBatis的两个配置文件

核心配置文件:包含数据源、事务、映射文件的配置
mybatis-config.xml:

<?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="test">
        <environment id="test">
       		<!--使用什么技术访问数据库-->
            <transactionManager type="JDBC"></transactionManager>
            <!--指定数据源的节点-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="数据库账号"/>
                <property name="password" value="数据库密码"/>
            </dataSource>
        </environment>
    </environments>
    <!-- MyBatis可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃 -->
	<!-- databaseIdProvider的type属性是必须的,不配置时会报错。DB_VENDOR这个属性值使用的是VendorDatabaseIdProvider类的别名 -->
	<databaseIdProvider type="DB_VENDOR">
		<!--property子元素是配置一个数据库,其中的name属性是数据库名称,value是我们自定义的别名,通过别名我们可以在SQL语句中标识适用于哪种数据库运行。-->
    	<property name="MySQL" value="mysql" />
    	<!-- 通过<select>等等标签添加databaseId="mysql"即可 -->
    	<property name="Oracle" value="oracle" />
	</databaseIdProvider>
	
    <!--·用来引入映射文件,底层维护了MapperRegistry,用来存各科Mapper文件-->
    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
        <mapper resource="mappers/DeptMapper.xml"/>
    </mappers>
</configuration>

映射文件: 里面有大量的SQL
XXX Mapper.xml:

<?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">
<!--映射文件,用来写大量SQL语句-->
<mapper namespace="cn.learning.mybatis.dao.DeptDao">
    <!--Id是每条数据的唯一标识-->
	<!--resultType属性用来完成ORM,把表里每个字段的值自动映射给类里的属性 -->
    <select id="getAll" resultType="类的全路径">
        select * from dept
    </select>

    <select id="getById" resultType="类的全路径">
        select * from dept where id = 1
    </select>

    <insert id="addOne">
        insert into dept values(11,'全栈','三区')
    </insert>
</mapper>

当SQL中有特殊字符,mybatis不能正常解析时可以使用该方法:

<![CDATA[
	and age<=#{age}
]]>

xml中&是用:&amp;编译时自动转换成&


Mybatis面向接口编程时注意事项

  • 需要在dao层创建表的对应类,且类名须和表名相同,参数与属性相同(大小写忽视)
  • 需要在dao层创建该实体类的接口实现程序所需要的增删改查功能,需要继承Mapper接口
  • Mapper.xml配置中mapper节点下的namespace属性必须和对应接口包的全路径相同
  • 对数据库操作的节点如:select或insert等:id属性必须和接口中方法名相同
  • Sql语句最后千万不能加分号 因为版本冲突严重(mysql可以, oraclet不可以)

注意好以上几点,Mybatis就可以自动完成对接口的映射,实现该接口的虚拟子类
Mybatis框架会在内存里面根据接口类型自动创建出一个接口的子类

Mybatis使用动态SQL

使用动态SQL先要定义XXXMapper.xml中查询节点下的SQL语句

<select id="getById" resultType="cn.learning.mybatis.dao.impl.Dept">
    select * from dept where id = #{id}
    select * from dept where id = ${id}
</select>
  • 以上两种方式#{}和${}都可以达到动态查询的效果
  • {}内的值必须和定义的Dao接口中的方法参数名字相同(映射的方法参数名相同)

#{id}与${id}实现相同的功能,但区别是:

强烈推荐#{}赋值方式:

使用#{parameterName}引用参数的时候,Mybatis会把这个参数认为是一个字符串例如:
Select * from emp where name = #{Smith}
使用时会自动转换: Select * from emp where name =‘Smith’
使用#{}可以从对象中获取指定的属性的值 ,有预编译的效果防止SqL注入攻击

使用#{}的好处

  • 这种写法可以防止SQL注入,而且会自动拼接字符串,高效安全避免了SQL攻击问题
  • #{}的参数还可以自动转换类型,无需担心数据类型的问题

能不就不用${}赋值:

使用${parameterName}引用参数的时,Mybatis会把这个参数认为是一个数字例如:
Select * from emp where name = ${employeeName}
使用时会自动转换:Select * from emp where name = Smith

使用${}的缺点

  • 存在SQL注入问题,如果字段是varchar类型直接抛出SQL异常。
  • 从安全性上考虑,能使用#尽量使用#来传参,因为这样可以有效防止SQL注入的问题。

Mybytis实现表主键自动回显

使用场景
当多表关联时,往往会在第一张表插入数据后,需要用该表中id与第二张表的id关联。
由于id是主键自增,我们无法获取到第一张表中新插入的id,所以使用Mybytis的主键自动回显功能


设置主键自动回显
在Mybytis的Mapper.xml配置映射关系时加入如下属性:

<insert id="xxxx" useGeneratedKeys="true" keyProperty="类的属性id" keyColumn="数据库字段id">
</insert>

useGeneratedKeys: true 表示开启Mybytis主键自动回显功能
keyProperty: 设置类中对应数据表中的主键变量名
keyColumn: 设置数据库的主键字段名\


当调用该插入的方法成功后,mybytis会自动注入到该对象主键的值即可调用

扩展:MyBatis Plus中Mapper接口已经实现了主键自动回显无需配置



ResultMap和resultType的区别

一般条件下,单表查询都使用resultType,多表关联查询时使用resultMap

resultType:

  • 完成ORM的映射关系,并且把结果集转换成一个resultType指定的对象实例
  • 但注意当字段名与属性名无法相同时必须使用ResultMap属性

ResultMap:

  • 用于对复杂对象结构时,对应的ResultMap结构名称。
  • 如数据库表的字段无法与类中成员属性名相同时使用

MyBatis提供了SQL标签

if / where / set / foreach

<!--where语法-->
<select id="getById" resultType="Car">
   select * from car where
   <where>
       id = #{id}
   </where>
</select>

<!--if语法-->
<select id="getByName" resultType="Car">
   select * from car
   <where>
       <if test="name ==值">
           name = #{name}
       </if>
   </where>
</select>

<update id="updateUser_if_set" parameterType="com.pojo.User">  
    UPDATE user  
    <set>  
        <if test="username!= null and username != '' ">  
            username = #{username},  
        </if>  
        <if test="sex!= null and sex!= '' ">  
           sex = #{sex},  
        </if>  
        <if test="birthday != null ">  
            birthday = #{birthday},  
        </if>  
    </set>  
    WHERE user_id = #{userid};      
</update>  

<!--foreach语法-->
<select id="getbyids" resultType="Car">
    select * from car where id in
    <foreach collection="" open="(" close=")" separator="," item="i">
       #{i}
    </foreach>
</select>

为什么要使用<if><where>呢?

首先使用标签方式写入SQL
XML代码片段

<mapper namespace="cn.learning.dao.DeptDao">
    <select id="getAll" resultType="cn.learning.mybatis.dao.impl.Dept">
        select * from dept
        <where>
            <if test="dname !=null">
            dname = #{dname}
            </if>
            and
            <if test="loc !=null">
                loc = #{loc}
            </if>
        </where>
    </select>
</mapper>

JAVA代码片段

List<Dept> allList = deptDao.getAll(null,"二区");

Mybatis生成SQL语句

select * from dept WHERE loc = ?

查询结果

Dept{id=2, dname='哈哈哈哈', loc='二区'}
Dept{id=3, dname='operations', loc='二区'}

使用SQL语法方式写入:
XML代码片段

<mapper namespace="cn.learning.mybatis.dao.DeptDao">
    <select id="getAll" resultType="cn.learning.mybatis.dao.impl.Dept">
      select * from dept where dname = #{dname} and loc = #{loc}
    </select>
</mapper>

java代码片段

List<Dept> allList = deptDao.getAll(null,"二区");

Mybatis生成SQL语句

select * from dept where dname = ? and loc = ?

查询结果

null(未查询到任何数据)

使用标签和不使用标签的总结:
使用标签:

如果SQL传参为空会自动把为空的SQL参数名以及参数和and或者Or删除只拼接有参数的数据
使用标签时面对复杂的业务时须要使用的

不使用标签

如果SQL传参为空:不会删除任何sql语句,而是在为空的参数后面=null and …
所以如果想使用动态sql语句,必须要使用标签的方式

SpringBoot整合Mybytis

  1. SpringBoot核心配置需要配置(驱动/配置文件目录/URL/账号/密码/XML文件目录/开启驼峰映射映射)
  2. 设置Dao的接口能被Mybatis读取到(接口中:@Mapper或者启动类@MapperScan(“Dao的全路径”)选择一种配置就行
  3. 一个Dao的接口须实现一个Mapper.xml文件(配置好 接口 / 接口方法 / 实体类 / 之间的映射),Mybytis会在内存自动实现实体类
  4. 调用时成员属性引用Dao的接口,用@Autowired会自动注入

Spring整合Mybytis的运行逻辑

  1. SprinaBoot程序启动时会加载pom.xml文件中指定的iar包
  2. 文件根据开箱用的原则则开始执行Mybatis代码
  3. SpringBoot程序加载Mybatis的iar包文件之后,通过yml配置文件实现数据的填充配置Mybaits相关信息
  4. 被SpringBoot整合后为简化代码结构Spring动态的为Mybatis的接口创建代理对象(启动类须加入@MapperScan…)
  5. 根据原有接口的模型,在运行期,通过Mapper.xml文件动态映射创建了一个一模一样功能的实例化子对象
  6. 通过注解@Autowired自动注入到指定引用对象上

Mybytis-SQL的两种写法方式

  1. 将所有的Sql语句都写到xml 映射文件中 :是万能的操作
  2. 将SQL通过注解的方式标识在接口方法上(只适用于简单操作)

通过注解一般都是操作简单的数据查询
如果遇到关联查询/复杂Sql则使用Mapper映射文件的方式 更加通用

JDBC和MyBatis的区别?

JDBC是java提供了一套专门用于和数据库对接的api,java.sql.*,其规范了如何和数据库进行对接,实现由各数据库厂商进行各自的实现和扩展。学习JDBC重点在学习如何使用其api。

MyBatis框架是轻量级封装了JDBC,我们已经看不到这些api,连接connection、语句preparedstatement、结果集ResultSet,而关注的是mybatis框架体系如何去使用,一旦写好,我们关注的是java对象。

XML和接口方式的区别?

MyBatis提供了两种操作数据库的方式,一种是通过xml映射文件,一种是通过java的接口类。按面向对象方式更加推荐接口方式,但如果复杂的多表映射,仍然需要使用xml映射文件的ResultMap方式实现。

接口只是假象,其底层仍然是通过xml实现,好不容易实现了一套方式,怎忍丢掉呢?可以做个测试就知道它底层怎么实现的?把xml中的sql删除,它就玩不转了。

SQL优化

与数据库交互的频次太多,会导致DB服务器性能出现问题
尽量避免一个请求业务须多次与数据库交互的操作来完成业务需求

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值