MyBatis

目录

    • 一、Mybatis 概述
      • 1.1 MyBatis 简介
      • 1.2 MyBatis 架构
    • 二、Mybatis 的引入
      • 2.1 持久化
      • 2.2 持久层
      • 2.3 为什么需要Mybatis?
    • 三、快速入门
      • 3.1 配置文件实现
        • 3.1.1 搭建测试数据库
        • 3.1.2 通过maven导入相关jar包(pom.xml)
        • 3.1.3 编写实体类
        • 3.1.4 编写持久层接口
        • 3.1.5 编写映射文件
        • 3.1.6 编写配置文件
        • 3.1.7 注意事项
        • 3.1.8 测试
        • 3.1.9 映射文件UserDao.xml中插入、更新、删除等
      • 3.2 注解实现
        • 3.2.1 pom.xml
        • 3.2.2 编写实体类
        • 3.2.3 编写持久层接口
        • 3.2.4 编写配置文件
        • 3.2.5 测试
    • 四、#{} 和 ${} 的区别
    • 五、MyBatis连接池
    • 六、MyBatis事务和动态SQL
      • 6.1 MyBatis事务
      • 6.2 动态SQL
    • 七、注解
      • 7.1 常用注解
      • 7.2 复杂注解
    • 八、MyBatis的延迟加载
      • 8.1 一对一(多对一)延迟加载
      • 8.2 一对多延迟加载
    • 九、MyBatis的缓存
      • 9.1 一级缓存
      • 9.2 二级缓存
      • 9.3 注解方式开启二级缓存

一、Mybatis 概述

MyBatis_第1张图片

1.1 MyBatis 简介

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

  • mybatis内部封装了 jdbc,使开发者只需要关注 sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。
  • mybatis通过xml 或注解的方式将要执行的各种statement配置起来,并通过java对象和statement 中 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并 返回。
  • 采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc进行了封装,屏蔽了 jdbc api 底层访问细节,使我 们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。

Mybatis中文文档 : http://www.mybatis.org/mybatis-3/zh/index.html
GitHub:https://github.com/mybatis/mybatis-3

1.2 MyBatis 架构

MyBatis架构如下:
MyBatis_第2张图片

各模块解释如下:
MyBatis_第3张图片

二、Mybatis 的引入

2.1 持久化

持久化是将程序数据在持久状态和瞬时状态间转换的机制。

  • 把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等。
  • JDBC就是一种持久化机制。文件IO也是一种持久化机制。
  • 内存断电后数据会丢失,但有一些对象是无论如何都不能丢失的,比如银行账号等,但人们还无法保证内存永不掉电。内存过于昂贵,与硬盘、光盘等外存相比,内存的价格要高2~3个数量级,而且维持成本也高,至少需要一直供电。因此,需要将数据持久化到外村。
  • 另一方面,即使对象不需要永久保存,也会因为内存的容量限制不能一直放在内存中,需要持久化来缓存到外存。

2.2 持久层

  • 持久层代码块是完成持久化工作的代码块,也就是dao层 【DAO (Data Access Object) 数据访问对象】
  • 大多数情况下特别是企业级应用,数据持久化往往也就意味着将内存中的数据保存到磁盘上加以固化,而持久化的实现过程则大多通过各种数据库来完成。
  • 不过这里有一个字需要特别强调,也就是所谓的“层”。对于应用系统而言,数据持久功能大多是必不可少的组成部分。之所以要独立出一个“持久层”的概念,而不是“持久模块”,“持久单元”,也就意味着,我们的系统架构中,应该有一个相对独立的逻辑层面,专注于数据持久化逻辑的实现.
  • 与系统其他部分相对而言,这个层面应该具有一个较为清晰和严格的逻辑边界。

2.3 为什么需要Mybatis?

Mybatis就是帮助程序猿将数据存入数据库中,和从数据库中取数据。传统的jdbc操作,有很多重复代码块。比如:数据取出时的封装,数据库的建立连接等等…,通过框架可以减少重复代码,提高开发效率。

MyBatis 是一个半自动化的ORM框架 (Object Relationship Mapping,对象关系映射),所有的事情,不用Mybatis依旧可以做到,只是用了它,所有实现会更加简单!

MyBatis的优点:

  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件就可以了,易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
  • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
  • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
  • 提供xml标签,支持编写动态sql。

三、快速入门

mybatis主要有两种实现方式,一种是通过配置文件实现,另一种是通过注解的方式实现。

3.1 配置文件实现

3.1.1 搭建测试数据库

CREATE DATABASE `mybatis`;
USE `mybatis`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (`id` int(20) NOT NULL, `username` varchar(20) DEFAULT NULL,
`pwd` varchar(40) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert  into `user`(`id`,`username`,`pwd`) values (1,'xiaoming','123456'),(2,'张三','2345678'),(3,'李四','3456789');

3.1.2 通过maven导入相关jar包(pom.xml)


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>com.yuangroupId>
    <artifactId>note_mybaties_01artifactId>
    <version>1.0-SNAPSHOTversion>
    <packaging>jarpackaging>

    <dependencies>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.4.5version>
        dependency>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.10version>
            <scope>testscope>
        dependency>
        <dependency>
            
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.6version>
            <scope>runtimescope>
        dependency>
        <dependency>
            
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>1.2.12version>
        dependency>
    dependencies>
    
    <build>
        <resources>
            <resource>
                <directory>src/main/resourcesdirectory>
                <includes>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>truefiltering>
            resource>
            <resource>
                <directory>src/main/javadirectory>
                <includes>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>truefiltering>
            resource>
        resources>
    build>
project>

3.1.3 编写实体类

路径com/lyl/entity/User.java

package com.lyl.entity;

import java.io.Serializable;
import java.util.Date;

@Data
public class User implements Serializable{
    private Integer id;
    private String  username;
    private String  pwd;
}

3.1.4 编写持久层接口

路径com/lyl/dao/UserDao.java

package com.lyl.dao;

import com.lyl.entity.User;
import java.util.List;

/**
 * 用户的持久层接口
 */
public interface UserDao {
    List<User> findAll();
}

3.1.5 编写映射文件

路径:resources/lyl/dao/UserDao.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.lyl.dao.UserDao">
    
    <select id="findAll" resultType="com.lyl.entity.User">
        SELECT * FROM USER
    select>
mapper>

3.1.6 编写配置文件

路径:resources/SqlMapConfig .xml


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
        
    <environments default="mysql">
        
        <environment id="mysql">
            
            <transactionManager type="JDBC">transactionManager>
            
            <dataSource type="POOLED">
            
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///数据库名"/>
                <property name="username" value="数据库账户"/>
                <property name="password" value="数据库密码"/>
            dataSource>
        environment>
    environments>

<mappers>
    <mapper resource="com/lyl/dao/UserDao.xml"/>
mappers>
configuration>

数据库也可以通过如下方式配置:

  • 编写一个配置文件db.properties
    driver=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useSSL=true&useUnicode=true&characterEncoding=UTF-8
    username=root
    password=123456
    
  • 对应的配置文件SqlMapConfig .xml如下:
    
    DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <properties resource="org/mybatis/example/config.properties">
    	<property name="username" value="dev_user"/>
    	<property name="password" value="F2Fa3!33TYyg"/>
    properties>
    <configuration>
    	
        
        <environments default="mysql">
            
            <environment id="mysql">
                
                <transactionManager type="JDBC">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>
    	
    	<mappers>
    	    <mapper resource="com/lyl/dao/UserDao.xml"/>
    	mappers>
    configuration>
    

3.1.7 注意事项

  • 创建UserDao.xml 和 UserDao.java时名称是为了和我们之前的知识保持一致。在Mybatis中它把持久层的操作接口名称和映射文件也叫做:Mapper。所以,UserDao 和 UserMapper是一样的
  • 在idea中创建目录的时候,它和包是不一样的。
    • 包在创建时:com.lyl.dao它是三级结构
    • 目录在创建时:com.lyl.dao是一级目录
  • mybatis的映射配置文件位置必须和dao接口的包结构相同
  • 映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名
  • 映射配置文件的操作配置(select),id属性的取值必须是dao接口的方法名
  • 当我们遵从了第三,四,五点之后,我们在开发中就无须再写dao的实现类。

3.1.8 测试

package com.lyl.test;

import com.lyl.dao.UserDao;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;

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

public class UserDaoTest {
    InputStream is = null;
    SqlSessionFactory factory = null;
    SqlSession session = null;

    @Before
    public void init() throws IOException {
        //读取配置文件
        is = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建会话工厂
        factory = new SqlSessionFactoryBuilder().build(is);
        //生产SQLSession对象
        session = factory.openSession();
    }
    
    @After
    public void close() throws IOException {
        session.commit();
        session.close();
        is.close();
    }

    @Test
    public void findAllTest(){
        UserDao userDao = session.getMapper(UserDao.class);
        System.out.println(userDao.findAll());
    }
}

3.1.9 映射文件UserDao.xml中插入、更新、删除等

namespace:namespace中的包名要和Dao/Mapper接口的包名一致!

  • Insert
    <insert id="addUser" parameterType="com.lyl.entity.User">
    	insert into mybatis.user (id, username, pwd) values (#{id},#{username},#{pwd});
    insert>
    
  • update
    <update id="updateUser" parameterType="com.lyl.entity.User">
        update mybatis.user set username=#{username},pwd=#{pwd}  where id = #{id} ;
    update>
    
  • Delete
    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id = #{id};
    delete>
    

注意:

  • 增删改需要提交事务!
    • 手动提交
      sqlSession.commit();
    • 自动提交
      修改测试文件 UserDaoTest 中 init() 方法的 session:
      session = factory.openSession(true);
      

3.2 注解实现

3.2.1 pom.xml

与3.1.2相同

3.2.2 编写实体类

与3.1.3相同

3.2.3 编写持久层接口

package com.lyl.dao;

import com.lyl.entity.User;
import org.apache.ibatis.annotations.Select;
import java.util.List;

/**
 * 用户的持久层接口
 */
public interface UserDao {
    @Select("SELECT * FROM USER")
    List<User> findAll();
}

3.2.4 编写配置文件


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
        
    <environments default="mysql">
        
        <environment id="mysql">
            
            <transactionManager type="JDBC">transactionManager>
            
            <dataSource type="POOLED">
            
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///数据库名"/>
                <property name="username" value="数据库账户"/>
                <property name="password" value="数据库密码"/>
            dataSource>
        environment>
    environments>

<mappers>
    <mapper class="com.lyl.dao.UserDao"/>
mappers>
configuration>

3.2.5 测试

同3.1.8相同

四、#{} 和 ${} 的区别

#{}是预编译处理,${}是字符串替换。

  • #{}是 sql 的参数占位符,MyBatis 会将 sql 中的#{}替换为? 号,在 sql 执行前会使用 PreparedStatement 的参数设置方法,按序给 sql 的? 号占位符设置参数值,比如 ps.setInt(0, parameterValue),#{item.name} 的取值方式为使用反射从参数对象中获取 item 对象的 name 属性值,相当于 param.getItem().getName()。
  • ${}是 Properties 文件中的变量占位符,它可以用于标签属性值和 sql 内部,属于静态文本替换,比如${driver}会被静态替换为com.mysql.jdbc. Driver

五、MyBatis连接池

使用了同步代码快保障了每一个线程拿到的是不同的连接,是一个线程安全的集合。
主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接池方式。

  • POOLED
    ​ 从池中获取连接,采用传统的 javax.sql.DataSource 规范中的连接池,mybatis 中有针对规范的实现。
  • UNPOOLE
    每次new一个连接,采用传统的获取连接的方式,虽然也实现 Javax.sql.DataSource 接口,但是并没有使用池的思想。
  • JNDI
    采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不一样。
    注意:如果不是web或者maven的war工程,是不能使用的。tomcat服务器,采用连接池就是dbcp连接池。

六、MyBatis事务和动态SQL

6.1 MyBatis事务

//生产SQLSession对象 session = factory.openSession(true);
//它是通过sqlsession对象的commit方法和rollback方法实现事务的提交和回滚

session.commit();
session.close();

6.2 动态SQL

<where>
<if>
<foreach>
这是一个根据条件查询的语句,但是条件有可能有,也有可能没有,就要使用动态SQL标签了[ids是Vo类里的属性名]
<include><sql id="defUser"> SELECT * FROM USER sql>
        <select id="findUserIn" resultType="User" parameterType="QueryVo">
    <include refid="defUser"/>
    <where>
        <if test="#{ids!= null and ids.size > 0 }">
            id in
            <foreach collection="ids " open="(" close=")" item="id" separator=",">
                #{id}
            foreach>
        if>
    where>
select>

七、注解

7.1 常用注解

@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@ResultMap:实现引用@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用

7.2 复杂注解

  • @Results 注解代替的是标签 , 该注解中可以使用单个@Result 注解,也可以使用@Result 集合 @Results({@Result(),@Result()})或@Results(@Result())

  • @Resutl 注解代替了 标签和标签 , @Result 中 属性介绍:

    • id 是否是主键字段
    • column 数据库的列名
    • property 需要装配的属性名
    • one 需要使用的@One 注解(@Result(one=@One)()))
    • many 需要使用的@Many 注解(@Result(many=@many)()))
  • @One 注解(一对一)
    代替了标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
    @One 注解属性介绍:

    • select 指定用来多表查询的
    • sqlmapper fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。
      使用格式:
      @Result(column=" “,property=”“,one=@One(select=”"))
  • @Many 注解(多对一), 代替了标签, 是多表查询的关键,在注解中用来指定子查询返回对象集合。
    注意: 聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType (一般为 ArrayList)但是注解中可以不定义;
    使用格式@Result(property="",column="",many=@Many(select=""))

八、MyBatis的延迟加载

8.1 一对一(多对一)延迟加载

<resultMap id="accountUserMap" type="account">
    <id property="id" column="id"/>
    <result property="uid" column="uid"/>
    <result property="money" column="money"/>
	
	<association
	        property="users"
	        column="uid"
	        javaType="user"
	        select="com.yuan.dao.UserDao.findById"
	/>
resultMap>


<select id="findAll" resultMap="accountUserMap">
    SELECT * FROM ACCOUNT
select>

8.2 一对多延迟加载

<resultMap id="userAccountMap" type="user">
    <id property="id" column="id">id>
    <result property="username" column="username"/>
    <result property="birthday" column="birthday"/>
    <result property="sex" column="sex"/>
    <result property="address" column="address"/>
    
        
        
    
    
    <collection
            property="accounts"
            column = "id"
            select="com.yuan.dao.AccountDao.findByUid"
            ofType="account"/>
resultMap>


<select id="findAll" resultMap="userAccountMap">
    SELECT * FROM USER
select>

九、MyBatis的缓存

像大多数的持久化框架一样,Mybatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提 高性能。 Mybatis 中缓存分为一级缓存,二级缓存。
MyBatis_第4张图片

9.1 一级缓存

一级缓存指的是Mybatis中SqlSession对象的缓存。
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。该区域的结构是一个Map。当我们再次查询同样的数据时,mybatis会先去sqlsession中查询是否有该数据,有的话直接拿出来用。当SqlSession对象消失时,mybatis的一级缓存也就消失了。

一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在,默认是开启的。当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。

9.2 二级缓存

二级缓存指的是Mybatis中SqlSessionFactory对象的缓存。 由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
二级缓存(默认开启)的使用步骤:

  • 第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
    
    <settings>
        <setting name="cacheEnabled" value="true"/>
    settings>
    
  • 第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
    添加标签【在映射文件中添加了这个标签就完事了】
  • 第三步: 在select标签添加属性 useCache=“true”

注意: 当我们在使用二级缓存时,所缓存的类一定要实现 java.io.Serializable 接口,这种就可以使用序列化方式来保存对象。

9.3 注解方式开启二级缓存

第一步: 配置文件开启二级缓存
第二步: 在接口文件接口名上添加注解@CacheNamespace(blocking = true)

你可能感兴趣的:(Web开发,Spring,Java,mybatis,数据库,spring,maven)