MyBatis学习笔记

安装MaBatis

将下面的依赖导入maven即可安装

<dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
</dependency>

 使用MaBatis

使用MaBatis需要先创建一个配置文件和用于获取SqlSession对象的工具类

位置如下

 MyBatis.Java

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

import java.io.IOException;
import java.io.InputStream;

public class Mybatis {
private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = null;
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }

}

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">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
                <property name="url" value="jdbc:sqlserver://localhost:3379;DatabaseName=Smbms;useSSL=true;useUnicode=true;characterEncoding=UTF-8"/>
                <property name="username" value="sa"/>
                <property name="password" value="12345678"/>
<!--数据库连接-->
            </dataSource>
        </environment>
    </environments>
    
</configuration>

一个基础的mybatis文件需要创建java接口,xml文件和使用接口

 的类,还需要在mybatis-config.xml文件中注册新创建的xml文件

 一般的接口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">
<mapper namespace="填写接口文件位置,如com.dao.UserDao">
    <select id="接口函数名" parameterType="参数,如int" resultType="返回类型,如com.pojo.User">
        sql代码
    </select>
    <update id="接口函数名" parameterType="参数,如int" resultType="返回类型,如com.pojo.User">
        sql代码
    </update>
    <delete id="接口函数名" parameterType="参数,如int" resultType="返回类型,如com.pojo.User">
        sql代码
    </delete>
    <insert id="接口函数名" parameterType="参数,如int" resultType="返回类型,如com.pojo.User">
        sql代码
    </insert>
</mapper>

 parameterType值为接口函数传入参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。

在sql代码中使用传入的参数

在sql代码中直接使用 #{参数名} 即可使用参数,#{参数名}会在参数外添加""来防止sql注入

使用#{参数名}后的参数形式为  "参数值"  ,而${参数名}的参数显示为  参数值  ,有sql注入的风险

注册

在mybatis-config.xml文件的,<configuration></configuration>标签中插入下面的代码完成注册,接口名与xml文件同名
<mappers>
    <!-- 使用相对于类路径的资源引用 -->
    <mapper resource="com/dao/UserDao.xml"/>
    <!-- 将包内的映射器接口实现全部注册 -->
    <package name="com.dao"/><---->
    <!-- 使用完全限定资源定位符(URL) -->
    <mapper url=""/>
    <!-- 使用映射器接口实现类的完全限定类名 -->
    <mapper resource="com/dao/UserDao"/>
</mappers>

注册的mapper文件(xml文件)中,<configuration></configuration>标签的子标签有着严格的顺序要求,写错就会有如下报错,括号内部分就是报错内容提示的正确顺序

使用接口

public  void TestLimit(){
        SqlSession sqlSession = Mybatis.getSqlSession();
        UserDao mapper = sqlSession.getMapper(填接口名字.calss,如UserDao.class);
//现在使用“mapper.函数名字”使用函数
//如       mapper.userLimit();

        
//涉及到增删改需要添加
//      sqlSession.commit();
//用于提交事务
        sqlSession.close();

    }

配置(<configuration></configuration>)

属性(properties)

可以在mapper文件中引入设置好的属性,有三种方法

1.引入properties文件
然后将<properties resource="相对于mapper文件的位置"/>添加到<configuration</configuration>

 

2.在<properties></properties>标签中添加

<property name="" value=""/>
<properties resource="">
  <property name="" value=""/>
  <property name="" value=""/>
</properties>

 3.通过在 SqlSessionFactoryBuilder.build() 方法中传入属性值

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);

// ... 或者 ...

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);

3种方法设置的属性优先级

如果一个属性在不只一个地方进行了配置,那么,MyBatis 将按照下面的顺序来加载:

  • 首先读取在 properties 元素体内指定的属性。
  • 然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
  • 最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。

因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。

 属性作用

<!--设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。比如:-->

<dataSource type="POOLED">
  <property name="driver" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="${username}"/>
  <property name="password" value="${password}"/>
</dataSource>

设置(settings)

可以改变 MyBatis 的运行时行为

详细含义跳转配置_MyBatis中文网

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>

  <setting name="mapUnderscoreToCamelCase" value="false"/>
<!--是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。
默认为false,根据实际情况使用-->

  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

类型别名(typeAliases)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:

<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。见下面的例子:

@Alias("author")
public class Author {
    ...
}

下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。

别名映射的类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator

环境配置(environments)

MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。

不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

environments 元素定义了如何配置环境。

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <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>

注意一些关键点:

  • 默认使用的环境 ID(比如:default="development")。
  • 每个 environment 元素定义的环境 ID(比如:id="development")。
  • 事务管理器的配置(比如:type="JDBC")。
  • 数据源的配置(比如:type="POOLED")。

默认环境和环境 ID 顾名思义。 环境可以随意命名,但务必保证默认的环境 ID 要匹配其中一个环境 ID。

事务管理器(transactionManager)

建议设置为JDBC,不需要了解

数据源(dataSource)

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。

Mybatis生命周期和工作域

SqlSessionFactoryBuilder

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

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。每次使用完必须关闭

如下面代码中sqlSession.close();

public  void TestLimit(){
        SqlSession sqlSession = Mybatis.getSqlSession();
        UserDao mapper = sqlSession.getMapper(填接口名字.calss,如UserDao.class);
//现在使用“mapper.函数名字”使用函数
//如       mapper.userLimit();

        
//涉及到增删改需要添加
//      sqlSession.commit();
//用于提交事务

        sqlSession.close();

    }

日志log4j

在settings中设置

logPrefix指定 MyBatis 增加到日志名称的前缀。任何字符串
logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

 推荐使用LOG4J

 设置

<setting name="logImpl" value="LOG4J"/>

在maven中导入

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

在CLASSPATH下创建一个log4j配置文件log4j.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
log4j.appender.console.encoding=UTF-8
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/rz.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#设置输出日志文件编码(可以控制乱码情况)
log4j.appender.file.encoding=UTF-8

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

MyBatis运行流程

 结果映射resultMap

在mapper文件中设置,如果在mapper中没有显示的设置resultMap,那么MyBatis会自动生成一个resultMap,里面的property和column值相等,在settings中开启驼峰后会按照驼峰映射

<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id" />
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>

<select id="接口函数名" resultMap="userResultMap">
<!--resultMap的值要与<resultMap>标签的id值相等才会使用该resultMap-->
</select>

用法

当sql代码返回一个结果集时使用resultMap进行元素名映射

property值为类里面的元素名

column值为sql返回的列名

用以解决数据库列名与类元素名不一致

 高级结果映射

多对一

当sql返回的结果集需要装入一个java对象(外对象),而该Java对象(外对象)中还包含一个Java对象(里对象)时,可以在resultMap中用             

按查询嵌套处理


<resultMap id="userResultMap" type="User">
  <association property="外对象中的里对象名字" column="sql返回的一个列名,用于select的条件参数" javaType="里对象类型" select="子查询的id值"/>
</resultMap>
<select id="子查询的id值" resultType="里对象类型">
子查询
</select>

 按结果嵌套处理

<resultMap id="userResultMap" type="User">
        <association property="外对象中的里对象名字" javaType="里对象类型">
                <result property="里对象元素名字" column="sql返回的列名"/>
                <result property="里对象元素名字" column="sql返回的列名"/>
         </association>
</resultMap>

一对多 

当sql返回的结果集需要装入一个java对象,而该Java对象中还包含一个集合(如List<>)时,可以在resultMap中用 

  按结果嵌套处理

<resultMap id="" type="">
  <id property="" column="" />
  <result property="" column=""/>
  <collection property="对象中的集合属性名" ofType="对象中的集合的子元素类型名">
    <id property="" column=""/>
    <result property="" column=""/>
    <result property="" column=""/>
  </collection>
</resultMap>

 注意:association中是javaType,collection中是ofType

动态sql 

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

if

当test里的表达式成立时才会将if标签内的sql代码拼接,否则会舍弃

<select id=""
     resultType="">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <if test="参数名 != null">
    AND title like #{参数名}
  </if>
  <if test="参数名 != null and 参数名 != null">
    AND author_name like #{参数名}
  </if>
</select>

choose (when, otherwise)

类似于java的switch,将第一个test值为真的when中的代码拼接,都为假则拼接otherwise中的代码

<select id=""
     resultType="">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="参数名 != null">
      AND title like #{参数名}
    </when>
    <when test="参数名 != null and 参数名 != null">
      AND author_name like #{参数名}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>

trim (where, set)

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

<select id=""
     resultType="">
  SELECT * FROM BLOG
  <where>
    <if test="参数名 != null">
         state = #{参数名}
    </if>
    <if test="参数名 != null">
        AND title like #{参数名}
    </if>
    <if test="参数名 != null and 参数名 != null">
        AND author_name like #{参数名}
    </if>
  </where>
</select>

set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号,在update中使用

<update id="">
  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>

foreach

对集合进行遍历(尤其是在构建 IN 条件语句的时候)

<select id="" resultType="">
  SELECT *
  FROM POST P
  WHERE ID in
  <foreach item="迭代时的集合中的每个元素" index="迭代时的索引,可省略" collection="集合属性名"
      open="集合开始符,如(" separator="集合的每个元素分隔符,如," close="集合结束符,如)">
        #{item的值}
  </foreach>
</select>

 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值

 缓存

MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。

默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:

<cache/>

基本上就是这样。这个简单语句的效果如下:

  • 映射语句文件中的所有 select 语句的结果将会被缓存。
  • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
  • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
  • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
  • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
  • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

缓存只作用于 cache 标签所在的映射文件中的语句。如果你混合使用 Java API 和 XML 映射文件,在共用接口中的语句将不会被默认缓存。你需要使用 @CacheNamespaceRef 注解指定缓存作用域。

这些属性可以通过 cache 元素的属性来修改。比如:

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

可用的清除策略有:

  • LRU – 最近最少使用:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

默认的清除策略是 LRU。

flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。

size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。

readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。

 二级缓存是事务性的。这意味着,当 SqlSession 完成并提交时,或是完成并回滚,但没有执行 flushCache=true 的 insert/delete/update 语句时,缓存会获得更新。

一级缓存只在一次会话中有效,当会话关闭后,缓存会被清空

二级缓存 在一级缓存被清空时收入

缓存顺序

先走二级缓存,再走一级缓存,最后走数据库查询 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值