zoukankan      html  css  js  c++  java
  • 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+"	name:"+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版:

    Kotlin版:

    8 参考链接

  • 相关阅读:
    预热buffer pool
    MySQL · 性能优化· InnoDB buffer pool flush策略漫谈
    事务并发控制
    LOAD DATA INFILE – performance case study
    隐式锁
    percona-xtrabackup安装
    mysql 表空间及索引的查看方法
    mysql用户权限
    mysql修改数据库名
    MySQL对innodb某一个表进行移动
  • 原文地址:https://www.cnblogs.com/6b7b5fc3/p/13751495.html
Copyright © 2011-2022 走看看