初入mybatis

初入mybatis

初入mybatis(mybatis概述、mybats初体验、mybatis配置文件详解、dao层mapper动态代理)

1、概述

MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

1.1MyBatis的jar包

要使用 MyBatis, 只需将 mybatis-x.x.x.jar 文件置于 classpath 中即可。

如果使用 Maven 来构建项目,则需将下面的 dependency 代码置于 pom.xml 文件中:

<!-- 添加mybatis依赖 -->
<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis</artifactId>
   <version>3.2.8</version>
</dependency>

1.2.MyBatis的功能架构:

我们把Mybatis的功能架构分为三层:

  • API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
  • 数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
  • 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。

1.3.MyBatis的优缺点

优点:

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

缺点:

  • 当你使用mybatis编写SQL语句时工作量很大,尤其是字段多、关联表多时,sql语句超级复杂,更是如此。
  • SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。
  • 框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。
  • 二级缓存机制不佳

2、初体验mybatis程序

2.1 创建一个Maven项目

1、导入Mybaits依赖

<!--lombok插件(可选,这里为了方便使用了)-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.20</version>
    <scope>provided</scope>
</dependency>
<!--junit 测试 (必选,测试程序使用)-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>
<!--mysql驱动包 (必选,连接MySQL数据库使用)-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.35</version>
</dependency>
<!-- 添加mybatis依赖 (必选,mybatis框架jar包)-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.2.8</version>
</dependency>
<!--日志 (可选,日志jar,这是为了方便查看日志,选择了)-->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
    <scope>test</scope>
</dependency>

2、创建实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@AllArgsConstructor//全参构造
@NoArgsConstructor//无参构造
@Data//get set
@Accessors(chain = true)//链式写法
public class MpUser {
    private Integer uid;
    private String uname;
    private String usex;
    private String uphone;
}

3、数据库表

DROP TABLE IF EXISTS `mp_user`;
CREATE TABLE `mp_user` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `uname` varchar(256) DEFAULT NULL,
  `usex` varchar(20) DEFAULT NULL,
  `uphone` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;

INSERT INTO `mp_user` VALUES ('1', 'A', 'M', '1111111');

4、接口和实现类

import com.bean.MpUser;
public interface MpUserDao {
    //根据id查询信息
    MpUser lookUserById(Integer uid);
}
import com.bean.MpUser;
import com.dao.MpUserDao;
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 MpUserDaoImpl implements MpUserDao {
    @Override
    public MpUser lookUserById(Integer uid) {
        MpUser mpUser=null;
        try {
            //1.读取mybatis主配置文件
            InputStream inputStream = Resources.getResourceAsStream("Mybatis-config.xml");
            //2.创建SqlSessionFactory对象
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //3.创建SqlSession对象
            sqlSession = sessionFactory.openSession();
            //4、执行查询
            mpUser=sqlSession.selectOne("lookUserById",1);
            //5、事务提交
            sqlSession.commit();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
        return mpUser;
    }
}

5、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">
<!--注意下面的配置顺序environments、mappers-->
<configuration>
<!--这里default设置当前使用的配置-->
    <environments default="prod">
        <environment id="prod">
            <!--使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域-->
            <transactionManager type="JDBC"/>
            <!--使用数据池,复用实例-->
            <dataSource type="POOLED">
                <!--<property name="driver" value="com.mysql.jdbc.Driver"/>-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/javaweb?allowMultiQueries=true&amp;characterEncoding=utf-8&amp;useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
        <environment id="dev">
            <!--使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域-->
            <transactionManager type="JDBC"/>
            <!--使用数据池,复用实例-->
            <dataSource type="POOLED">
                <!--<property name="driver" value="com.mysql.jdbc.Driver"/>-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/javaweb?allowMultiQueries=true&amp;characterEncoding=utf-8&amp;useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mybatis/MpUserMapper.xml"></mapper>
    </mappers>
</configuration>

6、创建mapper映射文件
MpUserMapper.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.MpUserDao">
<!--namespace要保证唯一,一般可以使用dao接口的路径,当然不是必须,只要保证唯一即可 -->
    <select id="lookUserById" resultType="com.bean.MpUser" parameterType="java.lang.Integer">
        select * from mp_user where uid=#{uid}
    </select>
</mapper>

7、测试类

import com.bean.MpUser;
import com.impl.MpUserDaoImpl;
import org.junit.Test;

public class TestM {
    @Test
    public void testA(){
        MpUserDaoImpl mpUserDao=new MpUserDaoImpl();
        MpUser mpUser = mpUserDao.lookUserById(1);
        System.out.println(mpUser);
    }
}

8、目录结构
在这里插入图片描述
9、结果
在这里插入图片描述

2.2.mybatis工具类

仔细看impl类,你会发现mybatis这样使用很复杂,每次查询都要

//1.加载主配置文件
InputStream inputStream = Resources.getResourceAsStream("Mybatis-config.xml");
//2.创建SqlSessionFactory对象
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.创建SqlSession对象
sqlSession = sessionFactory.openSession();

现在创建一个工具类:

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.InputStream;

public class MybatisUtils {
	//初始化创建SqlSessionFactory
	private static SqlSessionFactory sqlSessionFactory = null;
	static{
		try{
			//读取mybaits-config.xml文件
			InputStream inputStream = Resources.getResourceAsStream("Mybatis-config.xml");
			sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	//获取SqlSession
	public static SqlSession getSqlSession(){
		return sqlSessionFactory.openSession();
	}
	//获取SqlSessionFactory
	public static SqlSessionFactory getSessionFactory(){
		return sqlSessionFactory;
	}
}

接着可以修改impl类

import com.bean.MpUser;
import com.dao.MpUserDao;
import com.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
public class MpUserDaoImpl implements MpUserDao {
    private SqlSession sqlSession;
    @Override
    public MpUser lookUserById(Integer uid) {
        sqlSession= MybatisUtils.getSqlSession();
        MpUser mpUser=sqlSession.selectOne("lookUserById",1);
        sqlSession.commit();
        sqlSession.close();
        return mpUser;
    }
}

2.3.namespace作用

在mybatis文件夹创建MpArticleMapper.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="mparticlemapper">
    <select id="lookUserById" resultType="com.bean.MpUser" parameterType="java.lang.Integer">
        select uname,usex,uphone from mp_user where uid=#{uid}
    </select>
</mapper>

注意这个mapper中的查询方法的id,在MpUserMapper.xml中已经存在。
然后在Mybatis-config.xml注册上

<mappers>
    <mapper resource="mybatis/MpUserMapper.xml"></mapper>
    <mapper resource="mybatis/MpArticleMapper.xml"></mapper>
</mappers>

接着继续执行刚刚的TestM,中的测试程序发现报错如下:
在这里插入图片描述

java.lang.IllegalArgumentException: lookUserById is ambiguous in Mapped Statements collection (try using the full name including the namespace, or rename one of the entries)

主要是因为两个XXmapper.xml中都存在lookUserById方法,故程序分不清去哪个中查询,此时应该修改Impl类。修改如下:

原:
sqlSession.selectOne("lookUserById",1);
现:
sqlSession.selectOne("com.dao.MpUserDao.lookUserById",1);

其中com.dao.MpUserDao就是mappernamespace名字,到这我想就不用多说了,你应该懂namespace的作用了,如果说你不想加namespace,解决方案:xml中的插入方法的id不能一样。

3、主配置文件详解

主配置文件名可以随意命名,其主要完成以下几个功能:

  • (1)注册存放DB连接四要素的属性文件
  • (2)注册实体类的全限定性类名的别名
  • (3)配置MyBatis运行环境,即数据源与事务管理器
  • (4)注册映射文件

3.1 从属性文件中读取DB连接四要素

1、mybatis文件夹下创建jdbc.poroperties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/javaweb?allowMultiQueries=true&amp;characterEncoding=utf-8&amp;useSSL=false
jdbc.username=root
jdbc.password=123456

2、修改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">
<!--注意下面的配置顺序environments、mappers-->
<configuration>
    <properties resource="mybatis/jdbc.poroperties"></properties>
    <environments default="prod">
        <environment id="prod">
            <!--使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域-->
            <transactionManager type="JDBC"/>
            <!--使用数据池,复用实例-->
            <dataSource type="POOLED">
                <!--<property name="driver" value="com.mysql.jdbc.Driver"/>-->
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mybatis/MpUserMapper.xml"></mapper>
        <mapper resource="mybatis/MpArticleMapper.xml"></mapper>
    </mappers>
</configuration>

3.2 指定实体类全限定性类名的别名

对于实体类的全限定性类名的别名指定方式,一般使用方式。这样做的好处是会将该包中所有实体类的简单类名指定为别名,写法简单方便。在Mybatis-config.xml添加如下内容

<typeAliases>
        <package name="com.bean"/>
</typeAliases>

注意此内容需要放置在<environments default="prod"></environments>内容上面

这样设置后,MpUserMapper.xml中的resultType="com.bean.MpUser"就可以就改成resultType="MpUser"了,这样简单多了。
不过,还有另外的指定方式:通过指定。type:全限定性类名alias:别名该方式的好处是,可以指定别名为简单类名以外的其它名称。当然,弊端是,必须逐个指定,比较繁琐。

<typeAliases>
        <typeAlias type="com.bean.MpUser" alias="mpuser"/>
</typeAliases>

除了自定义的类型的别名外,MyBatis还提供了内置的类型别名:
基本类型:
在这里插入图片描述

3.3 配置MyBatis的运行环境

配置MyBatis的运行环境,主要是配置数据源与事务管理器。

  • environments标签在中可以包含多个运行环境,但其default属性指定了当前MyBatis运行时所选择使用的环境。environmentid属性为当前定义的运行环境的名称,可以任意命名。该名称会作为的default属性的值出现。

  • transactionManager标签,该标签用于指定MyBatis所使用的事务管理器。MyBatis支持两种事务管理器类型:JDBCMANAGED

    • (1)JDBC:使用JDBC的事务管理机制。即,通过Connectioncommit()方法提交,通过rollback()方法回滚。但默认情况下,MyBatis将自动提交功能关闭了,改为了手动提交。即程序中需要显式的对事务进行提交或回滚。从日志的输出信息中可以看到。
    • (2)MANAGED:由容器来管理事务的整个生命周期(如Spring容器)
  • dataSource标签该标签用于配置MyBatis使用的数据源类型与数据库连接基本属性。常见有类型有:UNPOOLEDPOOLEDJDNI等。

    • (1)UNPOOLED :不使用连接池。即每次请求,都会为其创建一个DB连接,使用完毕后,会马上将此连接关闭。
    • (2)POOLED:使用数据库连接池来维护连接。
    • (3)JNDI:数据源可以定义到应用的外部,通过JNDI容器获取数据库连接。

3.4 指定映射文件

指定映射文件的方式有多种。但所有的方式,都是指定在mappers标签中的。
指定映射文件若映射文件只有一个,则可直接使用如下形式:

<mappers>
    <mapper resource="mybatis/MpUserMapper.xml"></mapper>
    <mapper resource="mybatis/MpArticleMapper.xml"></mapper>
</mappers>

class属性值为Dao接口的全类名
该方式的使用,需要满足以下几个要求:

  • (1)映射文件名要与Dao接口名称相同
  • (2)映射文件要与接口在同一包中
  • (3)映射文件中的namespace属性值为Dao接口的全类名
<mappers>
    <mapper class="com.dao.MpUserDao"/>
</mappers>

当映射文件较多时,也可以使用如下形式。其中package的name属性指定映射文件所存放的包。但,这种方式的使用需要满足以下几个条件:

  • (1)dao使用mapper动态代理实现(后面讲)
  • (2)映射文件名要与Dao接口名称相同
  • (3)映射文件要与接口在同一包中
  • (4)映射文件中的namespace属性值为Dao接口的全类名
<mappers>
        <package name="com.dao"/>
</mappers>

dao使用mapper动态代理实现目录结构:
在这里插入图片描述
MpUserDaoImpl 修改成如下内容

import com.bean.MpUser;
import com.dao.MpUser.MpUserMapper;
import com.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

public class MpUserDaoImpl implements MpUserMapper {
    private static MpUserMapper mpUserMapper;

    static {
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        mpUserMapper = sqlSession.getMapper(MpUserMapper.class);
    }

    @Override
    public MpUser LookUserById(Integer uid) {
        return mpUserMapper.LookUserById(1);
    }
}

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.limuke.top/archives/mybatis-1

Buy me a cup of coffee ☕.