乐趣区

关于spring:Spring学习笔记六MyBatis集成

1 概述

MyBaits是一个驰名的长久层框架,本文首先介绍了 MyBatis 的简略应用,接着与 Spring 进行整合,最初简略地应用了 Generator 去主动生成代码。

2 MyBatis简介

MyBatis原本是 Apache 的一个开源我的项目——iBatis,2010 年由 Apaceh Software Foundation 迁徙到了Google Code,并改名为MyBatis

MyBatis是一个基于 Java 的长久层框架,提供的长久层框架包含 SQL MapsData Access Objects,应用简略的 XML 或者注解用于配置映射,将接口和 POJO 映射成数据库中的记录,是一个玲珑、不便、高效、简略、间接、半自动化的长久层框架。

3 工作原理

上图:

  • 读取配置文件:mybatis-config.xml是全局 MyBatis 配置文件,配置了 MyBatis 运行环境信息
  • 加载映射文件:也就是 SQL 映射文件,配置了操作数据库的 SQL 语句
  • 结构会话工厂:通过配置文件结构会话工厂SqlSessionFactory
  • 创立会话对象:由上一步的会话工厂创立会话对象SqlSession
  • 获取 MapperStatement:通过用户调用的apiStatement ID获取 MapperStatement 对象
  • 输出参数映射:通过 ExecutorMapperStatement进行解析,将各种 Java 根本类型转化为 SQL 操作语句中的类型
  • 输入后果映射:JDBC执行 SQL 后,借助 MapperStatement 的映射关系将返回后果转化为 Java 根本类型并返回

4 MyBatis示例

首先先来看一下纯 MyBaits 的示例,没有整合 Spring,一个简略的Maven 工程,我的项目构造如下:

4.1 依赖

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

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
</dependency>

<!-- 驱动用的是 MySQL,版本请自行批改 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
</dependency>

Gradle

compile group: 'org.mybatis', name: 'mybatis', version: '3.5.5'
compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.21'

4.2 实体类

@Setter
@Getter
@Builder
public class User {
    private Integer id;
    private String name;

    @Override
    public String toString() {return "id:"+id+"\tname:"+name;}
}

4.3 映射文件

新建一个叫 UserMapper.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="UserMapper">
    <select id="selectById" parameterType="Integer" resultType="pers.entity.User">
        select * from user where id=#{id}
    </select>
    <select id="selectAll" resultType="pers.entity.User">
        select * from user
    </select>

    <insert id="insert" parameterType="pers.entity.User">
        INSERT INTO `user` (`id`,`name`)
        VALUES (#{id},#{name})
    </insert>

    <update id="update" parameterType="pers.entity.User">
        UPDATE `user` set `name`=#{name} where id=#{id}
    </update>

    <delete id="delete" parameterType="Integer">
        DELETE FROM `user` WHERE `id` = #{id}
    </delete>
</mapper>

映射文件是一个 XML 文件,根元素为 <mapper>,须要留神其中的namespace 属性,调用的时候通过该 namespace 调用。其中的子元素示意 SQL 语句:

  • <select>:查问,id指定了这条语句的 id 号,调用时通过 namespace.id 的形式调用,比方该条 select 须要通过 UserMapper.selectById 调用,parameterType指定参数类型,这里是一个 Integer 的参数,resultType指定返回类型,实体类
  • <insert>/<update>/<delete>:对应的插入 / 批改 / 删除语句
  • 对于占位符:#{}示意是占位符,相当于传统 JDBC 中的 ?#{id} 示意该占位符期待接管的参数名称为id

4.4 配置文件

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">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test"/>
                <property name="username" value="test"/>
                <property name="password" value="test"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mapper/UserMapper.xml" />
    </mappers>
</configuration>

指定了数据库的一些连贯属性还有 mapper 的地位。

4.5 测试

public class Main {public static void main(String[] args) {
        try
        {InputStream inputStream = Resources.getResourceAsStream("config/mybatis-config.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession session = factory.openSession();
            User user = session.selectOne("UserMapper.selectById",1);
            System.out.println(user);
            User user1 = User.builder().name("test").build();
            session.insert("UserMapper.insert",user1);
            user1.setName("222");
            session.update("UserMapper.update",user1);
            List<User> list = session.selectList("UserMapper.selectAll");
            list.forEach(System.out::println);
            session.delete("UserMapper.delete",1);
            session.commit();
            session.close();}
        catch (Exception e)
        {e.printStackTrace();
        }
    }
}

次要流程如下:

  • 读取配置文件:依据 org.apache.ibatis.io.Resources 读取配置文件 mybatis-config.xml,请留神配置文件的地位正确,这里的配置文件都放在resources 下,mybatis-config.xml放在其中的 config
  • 构建 Session:依据配置文件构建SqlSessionFactory 后,通过 openSession 创立Session
  • 业务操作:通过 sessionselectOne/insert/update等进行业务操作,这类操作带两个参数,第一个参数是 String,示意配置文件中的SQL 语句,采纳 namespace.id 的模式,比方这里的 UserMapper.xml 中申明 namespaceUserMapper,其中带有一条 idselectByIdselect 语句,因而调用时应用 UserMapper.selectById 的模式,第二个参数是一个Object,示意要传递的参数,也就是绑定到配置文件中对应占位符的值
  • 提交与敞开:业务操作实现后提交事务并敞开session

示例测试后果:

5 Spring整合示例

下面的例子只是为了演示 MyBatis 的根本应用,没有整合 Spring,这里的例子是把Spring 整合进来,流程也大略差不多,我的项目构造如下:

5.1 依赖

分为 5 类JAR

  • MyBatis须要的JAR
  • Spring须要的JAR
  • MyBatisSpring 整合的两头JAR
  • 数据库驱动JAR
  • 数据源JAR

残缺依赖如下:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.9.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.2.9.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>5.2.9.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.2.9.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.9.RELEASE</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.2.9.RELEASE</version>
</dependency>

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

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.5</version>
</dependency>

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.8.0</version>
</dependency>

Gradle

compile group: 'org.springframework', name: 'spring-beans', version: '5.2.9.RELEASE'
compile group: 'org.springframework', name: 'spring-context', version: '5.2.9.RELEASE'
compile group: 'org.springframework', name: 'spring-core', version: '5.2.9.RELEASE'
compile group: 'org.springframework', name: 'spring-tx', version: '5.2.9.RELEASE'
compile group: 'org.springframework', name: 'spring-jdbc', version: '5.2.9.RELEASE'
compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.21'
compile group: 'org.apache.commons', name: 'commons-dbcp2', version: '2.8.0'
compile group: 'org.mybatis', name: 'mybatis', version: '3.5.5'
compile group: 'org.mybatis', name: 'mybatis-spring', version: '2.0.5'

5.2 配置文件

配置文件分为三类:

  • MyBatis映射文件:编写 mapper 的中央,也就是业务须要的 SQL 语句
  • MyBatis全局配置文件:因为整合了 Spring,数据源的配置放在了Spring 的配置文件中,而只须要保留 mapper 的查找地位
  • Spring配置文件:配置数据源 + 事务管理 +MyBaitssqlSssionFactory+ 组件扫描

5.2.1 MyBatis映射文件

与下面的例子差不多,只是批改了 namespace包名. 类名 的模式:

<?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="pers.dao.UserDao">
    <select id="selectById" parameterType="Integer" resultType="pers.entity.User">
        select * from user where id=#{id}
    </select>
    <select id="selectAll" resultType="pers.entity.User">
        select * from user
    </select>

    <insert id="insert" parameterType="pers.entity.User">
        INSERT INTO `user` (`id`,`name`)
        VALUES (#{id},#{name})
    </insert>

    <update id="update" parameterType="pers.entity.User">
        UPDATE `user` set `name`=#{name} where id=#{id}
    </update>

    <delete id="delete" parameterType="Integer">
        DELETE FROM `user` WHERE `id` = #{id}
    </delete>
</mapper>

namespace须要与对应包名的带有 @Mapper 的类配置统一。

5.2.2 MyBatis配置文件

<?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>
    <mappers>
        <mapper resource="mapper/UserMapper.xml" />
    </mappers>
</configuration>

5.2.3 Spring配置文件

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd"
       >

    <context:component-scan base-package="pers.dao"/>
    <context:component-scan base-package="pers.service"/>
    <!-- 数据源 -->
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test"/>
        <property name="username" value="test"/>
        <property name="password" value="test"/>
        <!-- 最大连接数 + 最大闲暇数 + 初始连接数 -->
        <property name="maxTotal" value="30"/>
        <property name="maxIdle" value="10"/>
        <property name="initialSize" value="5"/>
    </bean>
    
    <!-- 事务管理 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource"  ref="dataSource"/>
    </bean>

    <!-- 开启事务注解 -->
    <tx:annotation-driven transaction-manager="txManager" />

    <!-- 创立 SqlSessionFactory Bean-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:config/mybatis-config.xml"/>
    </bean>

    <!-- 注解扫描,次要用于 @Mapper,会扫描 basePackge 下的 @Mapper 注解的接口并主动拆卸为 MyBatis 的映射接口 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="pers.dao"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>
</beans>

5.3 长久层

须要加上 @Mapper 注解,示意主动拆卸为 MyBatis 的映射接口,留神:

  • 映射文件中的 namespace 须要与 包名. 类名 对应,比方这里的包为 pers.dao,类名为UserDao,那么映射文件中的namespacepers.dao.UserDao
  • id须要与办法名对应,比方映射文件中的有一条 select 语句的 idselectById,那么办法就须要命名为selectById,且参数类型须要对应统一
@Repository
@Mapper
public interface UserDao {User selectById(Integer id);
    List<User> selectAll();
    int insert(User user);
    int update(User user);
    int delete(Integer id);
}

5.4 业务层

@Service
@Transactional
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MyBatisService {
    private final UserDao dao;

    public void test(){User user = dao.selectById(13);
        System.out.println(user);
        dao.insert(User.builder().name("333").build());
        dao.update(User.builder().name("88888").id(13).build());
        dao.selectAll().forEach(System.out::println);
        dao.delete(12);
        dao.selectAll().forEach(System.out::println);
    }
}

注入 UserDao 后进行简略的测试,后果如下:

6 主动生成代码

置信很多程序员也厌恶写又长又麻烦的 XML 配置文件,因而,MyBatis也提供了一个生成器插件,能够间接从表中生成实体类、dao接口以及映射文件,能够省去很多操作。

步骤如下:

  • 导入依赖
  • 编写 Generator 配置文件
  • 生成代码

6.1 依赖

其实就是退出一个插件:

<build>
    <plugins>
        <plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.4.0</version>
            <configuration>
                <!-- 在控制台打印执行日志 -->
                <verbose>true</verbose>
                <!-- 反复生成时会笼罩之前的文件 -->
                <overwrite>true</overwrite>
                <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>8.0.21</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

数据库驱动请对应批改。

至于 Gradle 版请看 Kotlin 版源码。

6.2 配置文件

这里是参考他人的配置文件,批改数据库连贯、表名、包名即可:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!-- context 是逆向工程的次要配置信息 -->
    <!-- id:起个名字 -->
    <!-- targetRuntime:设置生成的文件实用于那个 mybatis 版本 -->
    <context id="default" targetRuntime="MyBatis3">
        <!--optional, 指在创立 class 时,对正文进行管制 -->
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <!-- 是否去除主动生成的正文 true:是:false: 否 -->
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <!--jdbc 的数据库连贯 wg_insert 为数据库名字 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/test" userId="test" password="test" />
        <!-- 非必须,类型处理器,在数据库类型和 java 类型之间的转换管制 -->
        <javaTypeResolver>
            <!-- 默认状况下数据库中的 decimal,bigInt 在 Java 对应是 sql 下的 BigDecimal 类 -->
            <!-- 不是 double 和 long 类型 -->
            <!-- 应用罕用的根本类型代替 sql 包下的援用类型 -->
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <!-- targetPackage:生成的实体类所在的包 -->
        <!-- targetProject:生成的实体类所在的硬盘地位 -->
        <javaModelGenerator targetPackage="pers.entity"
                            targetProject="src/main/java">
            <!-- 是否容许子包 -->
            <property name="enableSubPackages" value="false"/>
            <!-- 是否对 modal 增加构造函数 -->
            <property name="constructorBased" value="true"/>
            <!-- 是否清理从数据库中查问出的字符串左右两边的空白字符 -->
            <property name="trimStrings" value="true"/>
            <!-- 建设 modal 对象是否不可扭转 即生成的 modal 对象不会有 setter 办法,只有构造方法 -->
            <property name="immutable" value="false"/>
        </javaModelGenerator>
        <!-- targetPackage 和 targetProject:生成的 mapper 文件的包和地位 -->
        <sqlMapGenerator targetPackage="mapper"
                         targetProject="src/main/resources">
            <!-- 针对数据库的一个配置,是否把 schema 作为字包名 -->
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>
        <!-- targetPackage 和 targetProject:生成的 interface 文件的包和地位 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="pers.dao" targetProject="src/main/java">
        </javaClientGenerator>
        <!-- tableName 是数据库中的表名,domainObjectName 是生成的 JAVA 模型名,前面的参数不必改,要生成更多的表就在上面持续加 table 标签 -->
        <table tableName="user" domainObjectName="User"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false" />
    </context>
</generatorConfiguration>

6.3 生成代码

双击生成即可:

生成了实体类、dao接口以及 mapper 文件。

7 参考源码

Java版:

  • Github
  • 码云
  • CODE.CHINA

Kotlin版:

  • Github
  • 码云
  • CODE.CHINA

8 参考链接

  • 简书 -IDEA 应用 mybatis-generator
  • Github-mybatis-generator-plugin
退出移动版