Data Access 之 MyBatis(二) - Configuration XML

2022-08-19 17:05:41 浏览数 (1)

一、MyBatis Configuration XML

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 configuration(配置)标签下主要有如下配置,配置的顺序要严格遵循列出的顺序

  • properties(属性)
  • settings(设置)
  • typeAliases(类型别名)
  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
  • environments(环境配置)
    • environment(环境变量)
      • transactionManager(事务管理器)
      • dataSource(数据源)
  • databaseIdProvider(数据库厂商标识)
  • mappers(映射器)

工程搭建

新建maven工程mybatis-config-xml,引入依赖

代码语言:javascript复制
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.16</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.18</version>
    <scope>provided</scope>
</dependency>

增加entity包,新增Employee实体类

代码语言:javascript复制
@Data
public class Employee {

    private Integer id;
    private String empName;
    private String email;
    private Integer gender;
}

增加dao包,新增EmployeeDao接口

代码语言:javascript复制
public interface EmployeeDao {

    Employee getEmpById(Integer id);
    int updateEmployee(Employee employee);
    boolean deleteEmployee(Integer id);
    int insertEmployee(Employee employee);
}

在resource目录下增加全局配置文件mybatis-config.xml

代码语言:javascript复制
<?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="dev">
        <!--配置环境,不同的环境不同的id名字-->
        <environment id="dev">
            <!-- 采用JDBC方式对数据库事务进行commit/rollback -->
            <transactionManager type="JDBC"></transactionManager>
            <!--采用连接池方式管理数据库连接-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&amp;amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

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

增加mappers文件夹,在其中增加employee.xml

代码语言:javascript复制
<?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.citi.dao.EmployeeDao">

    <!--参数类型不用写-->
    <select id="getEmpById" resultType="com.citi.entity.Employee">
        select * from t_employee where id = #{id}
    </select>

    <!--增删改不用写返回值类型,增删改返回的是影响了多少行,MyBatis自动判断
        如果是boolean,影响0行自动封装为false,否则为true,
        参数类型也不用写
        #{属性名}-->

    <update id="updateEmployee" parameterType="com.citi.entity.Employee">
        UPDATE t_employee
        SET empname = #{empName},
        gender = #{gender},
        email = #{email}
        WHERE id = #{id}
    </update>

    <delete id="deleteEmployee">
        DELETE FROM t_employee WHERE id = #{id}
    </delete>

    <insert id="insertEmployee" useGeneratedKeys="true" parameterType="com.citi.entity.Employee">
        INSERT INTO t_employee(empname,gender,email) values (#{empName},#{gender},#{email})
    </insert>
</mapper>

在resource目录下增加日志配置

代码语言:javascript复制
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
       <encoder>
           <pattern>[%thread] %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
       </encoder>
   </appender>

    <!--
        日志输出级别(优先级高到低):
        error: 错误 - 系统的故障日志
        warn: 警告 - 存在风险或使用不当的日志
        info: 一般性消息
        debug: 程序内部用于调试信息
        trace: 程序运行的跟踪信息
     -->
    <root level="debug">
        <appender-ref ref="console"/>
    </root>
</configuration>

新增EmployeeDaoTest测试类

代码语言:javascript复制
public class EmployeeDaoTest {

    SqlSessionFactory sqlSessionFactory = null;
    SqlSession openSession = null;

    @Before
    public void setUp() throws Exception {

        //1、根据全局配置文件创建出一个SqlSessionFactory
        //SqlSessionFactory:是SqlSession工厂,负责创建SqlSession对象;
        //SqlSession:sql会话(代表和数据库的一次会话);
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        openSession = sqlSessionFactory.openSession();

    }

    @Test
    public void getEmpById() throws Exception{

        EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
        Employee employee = employeeDao.getEmpById(1);

        System.out.println(employee);
    }


    @Test
    public void updateEmployee() {
        EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
        Employee updateEmployee = new Employee();
        updateEmployee.setId(1);
        updateEmployee.setEmpName("Tony Stark");
        updateEmployee.setEmail("stark@stark-industry.com");
        updateEmployee.setGender(0);
        employeeDao.updateEmployee(updateEmployee);

        Employee employee = employeeDao.getEmpById(1);
        System.out.println(employee);
    }

    @Test
    public void deleteEmployee() {

        EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
        System.out.println(employeeDao.getEmpById(6));

        boolean isDelete = employeeDao.deleteEmployee(6);
        System.out.println(isDelete);
    }

    @Test
    public void insertEmployee() {

        Employee employee = new Employee();
        employee.setEmpName("peter");
        employee.setGender(0);
        employee.setEmail("peter@gmail.com");

        EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
        employeeDao.insertEmployee(employee);
        System.out.println(employeeDao.getEmpById(2));
    }

    @After
    public void tearDown() throws Exception {

        openSession.close();
    }
}

执行测试方法,验证项目是否可以成功运行

properties属性-引入外部文件

在resource目录下新建db.properties,配置数据库连接信息

代码语言:javascript复制
jdbc_driver=com.mysql.cj.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true&amp;useSSL=false&amp;serverTimezone=Asia/Shanghai
jdbc_username=root
jdbc_password=root

修改mybatis全局配置文件,引入properties,并修改数据库连接配置

在configuration标签下增加properties标签

代码语言:javascript复制
<properties resource="db.properties" />

properties标签有两个属性,都可以标识引入文件的位置

  • resource:从类路径下开始引用
  • url:引用磁盘或者网络路径下的资源

修改datasource标签下的数据库连接配置,使用${}引用数据库配置文件的配置信息

代码语言:javascript复制
<dataSource type="POOLED">
    <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>

执行getEmpById测试方法

一定要将properties放在第一个,否则会报错

settings属性-改变MyBatis运行时行为

settings是MyBatis中极为重要的配置,它会改变MyBatis的运行时行为。 mapUnderscoreToCamelCase是否开启驼峰命名自动映射,即将数据库字段名 A_COLUMN 映射到实体类属性名 aColumn(数据库字段不区分大小写,但是区分是否有下划线“_”);默认是false即不开启

t_employee表增加一个字段create_time,并给字段赋值为当前时间,同时Employee实体类也需要增加一个属性createTime

代码语言:javascript复制
@Data
public class Employee {

    private Integer id;
    private String empName;
    private String email;
    private Integer gender;
    private Date createTime;
}

执行测试getEmpById()测试方法

createTime为空说明在数据库字段中没有找到createTime字段,而我们命名的字段为create_time,解决这个问题可以的办法是可以在修改SQL给查询字段增加别名使其与数据库字段一致害可以在mybatis全局配置中增加settings属性,开启自动驼峰命名转换,注意settings配置一定要在properties配置的下面

代码语言:javascript复制
<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
  • name:配置项的Key
  • value:配置项的值 可以配置的Key有很多,具体可以点击此处查看

再次执行测试

成功获取到了createTime的值

typeAliases属性-为类型起别名

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

代码语言:javascript复制
<typeAliases>
  <typeAlias alias="Employee" type="com.citi.entity.Employee"/>
</typeAliases>

alias指定一个别名,如果不指定,默认就是类名

在需要起别名的类非常多的时候,可以通过package属性批量起别名

代码语言:javascript复制
<typeAliases>
    <package name="com.citi.entity"/>
</typeAliases>

批量的时候如果需要对某个类起一个非默认的别名,可以在实体类上增加注解@Alias增加别名 修改映射文件employee.xml中select标签,将返回内容resultType从com.citi.entity.Employee改为Employee,定义类别名之后就可以识别到

代码语言:javascript复制
<select id="getEmpById" resultType="Employee">
    select * from t_employee where id = #{id}
</select>

再次执行测试

推荐使用全类名,可以快速定位

typeHandlers属性-类型处理器

MyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型。

代码语言:javascript复制
<typeHandlers>
    <!--配置自定义的类型处理器-->
    <typeHandler handler="自定义类型处理器" />
</typeHandlers>

MyBatis已经定义好了大部分的类型处理器,遇到枚举类型可能需要进行自定义类型处理器。该配置使用频次较低

objectFactory(对象工厂)

MyBatis将查询到的数据使用objectFactory利用反射封装成对象,使用频次较低

plugins属性

MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

插件通过动态代理机制,可以介入上面四大对象的任何一个方法的执行

environment属性-支持多环境切换

MyBatis通过environments标签配置多个环境,如开发、测试、生产环境等,可以通过default属性是指默认的环境或者切换环境

每一个environment指一个环境,id属性是这个环境的唯一标识

事务控制会使用Spring的事务控制,数据元配置会使用如druid、c3p0等数据库连接工具,不会使用原生的数据库驱动

databaseProvider-数据库移植

MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载带有匹配当前数据库 databaseId 属性和所有不带 databaseId 属性的语句

代码语言:javascript复制
<databaseIdProvider type="DB_VENDOR">
    <property name="MySQL" value="mysql"></property>
    <property name="Oracle" value="orcl"></property>
</databaseIdProvider>

SQL映射文件中可以根据不同的数据库增加不同的SQL语句

代码语言:javascript复制
<select id="getEmpById" resultType="Employee" databaseId="orcl">
    select * from t_employee where id = #{id}
</select>

使用频次较低

mappers-批量注册

我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等

代码语言:javascript复制
<!-- 使用相对于类路径的资源引用 -->
<mappers>
    <mapper resource="mappers/employee.xml"/>
</mappers>
代码语言:javascript复制
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/employee.xml"/>
</mappers>
代码语言:javascript复制
<!-- 使用映射器接口实现类的完全限定类名,要保证xml文件和接口名相同并在同一目录下-->
<mappers>
  <mapper class="com.citi.dao.EmployeeDao"/>
</mappers>
代码语言:javascript复制
<!-- 将包内的映射器接口实现全部注册为映射器,要保证xml文件和接口名相同并在同一目录下 -->
<mappers>
  <package name="com.citi.dao"/>
</mappers>

0 人点赞