MyBatis实战【上】

MyBatis

主要内容

  • Mybatis 入门
  • Mybatis 的基本使用 J
  • ava 日志处理框架
  • Mybatis 配置完善
  • SqlSession 常用 API
  • Mapper 动态代理
  • 动态 SQL
  • Mybatis 缓存
  • Mybatis 多表关联查询
  • Mybatis 注解的使用
  • Mybatis Generator 工具的使用
  • PageHelper 分页插件
  • Mybatis 与 Servlet 整合

一、MyBatis入门

MyBatis实战【上】_第1张图片

1 什么是框架

框架(Framework)是一个框子——指其约束性,也是一个架子——指其支撑性。是一个基本概念上的结构,用于去解决或者处理复杂的问题。框架这个广泛的定义使用的十分流行,尤其在软件概念。

框架( Framework )是构成一类特定软件可复用设计的一组相互协作的类。框架规定了 你的应用的体系结构。它定义了整体结构,类和对象的分割,各部分的主要责任,类和对象 怎么协作,以及控制流程。框架预定义了这些设计参数,以便于应用设计者或实现者能集中 精力于应用本身的特定细节。

如果将开发完成的软件比作是一套已经装修完毕的新房,那框架就好比是一套已经修建 好的毛坯房。用户直接购买毛坯房,建筑质量和户型合理有保证,还省去了自己建造房屋的 时间,一举多得。

在开发过程是使用框架,同样可以保证减少开发时间、降低开发难度,并且还保证设计质量。好比和世界上最优秀的软件工程师是一个项目的,并且他们完成的还是基础、全局的 工作。想想是不是很嗨的一件事情。

MyBatis实战【上】_第2张图片
框架还有一个作用是约束。莎士比亚说,“一千个观众眼中有一千个哈姆雷特” 即仁者见 仁,智者见智.说每个人都会对作品有不同的理解,每个人对待任何事物都有自己的看法,一 千个人就有可能有一千种不同的看法 1000 人心中有 1000 个哈姆雷特。同样的技术解决同 样的问题会产生不同流程和风格的解决方案,而采用一种框架其实就是限制用户必须使用其 规定的方案来实现,可以降低程序员之间沟通以及日后维护的成本。

总之,框架是一个半成品,已经对基础的代码进行了封装并提供相应的 API,开发者在 使用框架是直接调用封装好的 API 可以省去很多代码编写,从而提高工作效率和开发速度。

使用框架可以带来的好处:

  • 重用代码大大增加,软件生产效率和质量也得到了提高;
  • 代码结构的规范化,降低程序员之间沟通以及日后维护的成本;
  • 知识的积累,可以让那些经验丰富的人员去设计框架和领域构件,而不必限于低层编程;
  • 软件设计人员要专注于对领域的了解,使需求分析更充分;
  • 允许采用快速原型技术; 有利于在一个项目内多人协同工作;
  • 大粒度的重用使得平均开发费用降低,开发速度加快,开发人员减少,维护费用降低, 而参数化框架使得适应性、灵活性增强。

2 什么是 ORM

ORM,Object-Relationl Mapping,对象关系映射,它的作用是在关系型数据库和对 象之间作一个映射处理。

JDBC 的缺点:需要手动的完成面向对象的 Java 语言、面向关系的数据库之间数据的 转换,代码繁琐无技术含量,影响了开发效率。

如图所示,查询是需要手动的将结果集的列数据转换为 Java 对象的属性;而添加操作 时需要手动将 Java 对象的属性转换为数据库表的列字段。
MyBatis实战【上】_第3张图片
关于面向对象的 Java 语言、面向关系的数据库之间数据的转换必须要做,问题在于这个转换是否可以不由开发者来做?答案是可以的。ORM 框架就是专门来解决这个问题的, 相当于在面向对象语言和关系数据库之间搭建一个桥梁。这样我们在具体的操作数据库的时 候,只要像平时操作对象一样操作它就可以了,ORM 框架会根据映射完成对数据库的操作, 就不需要再去和复杂的 SQL 语句打交道了。
MyBatis实战【上】_第4张图片

3 MyBatis 简介

MyBatis 本是 Apache 的一个开源项目 iBatis, 2010 年这个项目由 Apache Software Foundation 迁移到了 Google Code,且改名为 MyBatis 。2013 年 11 月迁移到 GitHub。

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。 MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使 用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java 对象)映射成数据库中的记录。

简单的说:MyBatis 是一个半自动 ORM 框架,其本质是对 JDBC 的封装。使用 MyBatis 重点需要程序员编写 SQL 命令,不需要写一行 JDBC 代码。

与 Hibernate 的比较
Hibernate 是一个全自动的 ORM 框架。因为 Hibernate 创建了 Java 对象和数据库表 之间的完整映射,可以完全以面向对象的思想来操作数据库,程序员不需要手写 SQL 语句, 而 MyBatis 中还需要手写 SQL 语句,所以是半自动化的,工作量要大于 Hibernate。

为什么半自动化的 Mybatis 比自动化的 Hibernate 受欢迎?
MyBatis 需要手写 SQL 语句,所以工作量要大于Hibernate。但是也正是由于自定义 SQL 语句,所以其灵活性、可优化性就超过了 Hibernate。
MyBatis实战【上】_第5张图片
Hibernate 封装了 SQL 语句,由开发者对对象操作,Hibernate 来生成 SQL 语句。虽 然也可以通过映射配置来控制生成的 SQL 语句,但是对于要生成复杂的 SQL 语句,很难实 现,或者实现后导致性能的丢失。

而 MyBatis 将手写 SQL 语句的工作丢给开发者,可以更加精确的定义 SQL,更加灵活, 也便于优化性能。完成同样功能的两条 SQL 语句的性能可能相差十几倍到几十倍,在高并 发、快响应要求下的互联网系统中,对性能的影响更明显。

MyBatis 对存储过程可提供很好的支持。另外 MyBatis 的开发工作量大不意味着学习 成本大。对于新手,学习 Hibernate 时间成本比 Mybatis 大很多,Mybatis 很快就上手了。
MyBatis实战【上】_第6张图片
总之,因为 MyBatis 具有封装少、映射多样化、支持存储过程、可以进行 SQL 语句优 化等特点,符合互联网高并发、大数据、高性能、高响应的要求,使它取代 Hibernate 成 为了 Java 互联网中首选的持久框架。而对于对性能要求不高的比如内部管理系统、ERP 等 可以使用 Hibernate。

二、 Mybatis 的基本使用

1 Mybatis 的 jar 包下载地址

https://github.com/mybatis/mybatis-3/releases

2 Mybatis 的 jar 包介绍

MyBatis实战【上】_第7张图片
MyBatis实战【上】_第8张图片

3 核心 API 介绍

3.1核心 API

  • SqlSessionFactoryBuilder
    SqlSessionFactoryBuilder 的作用是使用构建者模式创建 SqlSessionFactory 接口 对象。

  • SqlSessionFactory
    SqlSessionFactory 可以被认为是一个数据库连接池,它的作用是创建 SqlSession 接口对象。

  • SqlSession
    如果说 SqlSessionFactory 相当于数据库连接池,那么 SqlSession 就相当于一个数 据库连接(Connection 对象),你可以在一个事务里面执行多条 SQL,然后通过它的 commit、rollback 方法提交或者回滚事务。

  • Mapper
    映射器。由一个 Java 接口和 XML 文件(或者注解构成),需要给出对应的 SQL 和映 射规则,负责发送 SQL 去执行并返回结果。

3.2核心 API 工作流程

MyBatis实战【上】_第9张图片

3.3生命周期

  • SqlSessionFactoryBuilder:
    该类用来创建 SqlSessionFactory 对象,当 SqlSessionFactory 对象被创建后, SqlSessionFactoryBuilder 就失去了作用,所以它只能存在于创建 SqlSessionFactory 的 方法中,而不要让其长期存在。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法 作用域。
  • SqlSessionFactory:
    SqlSessionFactory 的生命周期存在于整个 MyBatis 的应用之中,所以一旦创建了 SqlSessionFactory,就要长期保存它,直至不再使用 MyBatis 应用,所以可以认为 SqlSessionFactory 的生命周期就等同于 MyBatis 的应用周期。由于 SqlSessionFactory 是 一 个 对 数 据 库 的 连 接 池 , 所 以 它 占 据 着 数 据 库 的 连 接 资 源 。 如 果 创 建 多 个SqlSessionFactory,那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也 会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况。因 此 SqlSessionFactory 是一个单例,让它在应用中被共享。
  • SqlSession:
    SqlSession 应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让 它归还给 SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪,所以 用 try…catch…finally… 语句来保证其正确关闭。 所以 SqlSession 的最佳的作用域是请求或方法作用域。
  • Mapper:
    由于 SqlSession 的关闭,它的数据库连接资源也会消失,所以它的生命周期应该小 于等于 SqlSession 的生命周期。Mapper 代表的是一个请求中的业务处理,所以它应该 在一个请求中,一旦处理完了相关的业务,就应该废弃它。

4 Mybatis 的配置文件

https://mybatis.org/mybatis-3/zh/configuration.html
在 Mybatis 中配置文件有两种:

  • 全局配置文件
  • 映射配置文件

4.1全局配置文件

全局配置文件的名称是自定义的,在 JavaProject 项目中需要放到 src 目录下。
全局配置文件的作用是完成一些全局性的配置,如:对 Mybatis 框架的设置、别名设置、 环境设置、指定映射配置文件等相关配置。

 
DOCTYPE configuration 
PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-config.dtd"> 
<configuration> 

configuration>

4.1.1 properties 标签

Mybatis 配置文件中的属性定义。properties 标签中允许内部定义属性,也可以是外部的 properties 文件定义属性。无论是内部定义还是外部定义,都可以使用${name}获取值。
配置文件中内部定义

<properties> 
	<property name="jdbc.driver" value="com.mysql.jdbc.Driver"/> 
	<property name="jdbc.url" value="jdbc:mysql://localhost:3306/bjsxt"/> 
	<property name="jdbc.username" value="root"/> 
	<property name="jdbc.password" value="root"/> properties>

配置文件中外部定义

<properties resource="db.properties">properties>

4.1.2 settings 标签

setting 标签的配置是配置 MyBatis 框架运行时的一些行为的,例如缓存、延迟加载、 结果集控制、执行器、分页设置、命名规则等一系列控制性参数,其所有的 setting 配置都 放在父标签 settings 标签中。

<settings> 
	<setting name="cacheEnabled" value="true"/> 
	<setting name="lazyLoadingEnabled" value="true"/> 
	<setting name="multipleResultSetsEnabled" value="true"/> 
	<setting name="useColumnLabel" value="true"/> 
	<setting name="useGeneratedKeys" value="false"/>
	<setting name="autoMappingBehavior" value="PARTIAL"/> 
	<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/> 
	<setting name="defaultExecutorType" value="SIMPLE"/> 
	<setting name="defaultStatementTimeout" value="25"/> 
	<setting name="defaultFetchSize" value="100"/> 
	<setting name="safeRowBoundsEnabled" value="false"/> 
	<setting name="mapUnderscoreToCamelCase" value="false"/> 
	<setting name="localCacheScope" value="SESSION"/> 
	<setting name="jdbcTypeForNull" value="OTHER"/> 
	<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/> 
settings>

MyBatis实战【上】_第10张图片
MyBatis实战【上】_第11张图片

4.1.3 typeAliases 标签

类型别名可为 Java 类型设置一个缩写名字。

<typeAliases> 
	<typeAlias alias="user" type="com.bjsxt.pojo.User" /> 
typeAliases>

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean

<typeAliases> 
	<package name="com.bjsxt.pojo"/> 
typeAliases>

下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的
MyBatis实战【上】_第12张图片

4.1.4 environments 标签

MyBatis 可以配置多个环境。这可以帮助你 SQL 映射对应多种数据库等。比如说,想为 开发、测试、发布产品配置不同的环境。

<environments default="development"> 
	<environment id="development"> 
		<transactionManager type="JDBC"/> 
		<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>
	environment>
		<transactionManager type="JDBC"/> 
		<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> 
	environment> 
environments>		
4.1.4.1 transactionManager 节点

事务处理器。

在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]")

JDBC :这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来 管理事务作用域。

MANAGED :不做事务处理。

4.1.4.2 dataSource 标签
  • dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
  • UNPOOLED:使用直连。
  • POOLED:使用池连。
  • JNDI :使用 JNDI 方式连接

4.1.5 mapper 标签

指定映射配置文件
使用相对于类路径指定映射配置文件

<mappers> 
	<mapper resource="com/bjsxt/mapper/UserMapper.xml"/> 
mappers>

使用 filter:///协议指定映射配置文件

<mappers> 
	<mapper url="file:///D:\code\mybatis\src\com\bjsxt\mapper\UserMapper.xml" />
mappers>

指定映射接口

<mappers> 
	<mapper class="com.bjsxt.mapper.UserMapper"/> 
mappers>

通过包名指定映射接口

<mappers> 
	<package name="com.bjsxt.mapper"/> 
mappers>

4.2映射配置文件

映射配置文件主要是用来编写 sql 语句的,结果集的映射关系的指定,以及缓存的一些 配置等等。
MyBatis实战【上】_第13张图片

 
DOCTYPE mapper 
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 
<mapper namespace="com.bjsxt.mapper.UserMapper"> 

mapper>

4.2.1 resultMap 标签

指定查询结果集与对象的映射关系,是最复杂也是最强大的标签。
id:唯一标识。
type:类的完全名, 或者一个类型别名

<resultMap id="userMapper" type="com.bjsxt.pojo.User"> 
	<id property="userid" column="user_id"/> 
	<result property="username" column="user_name"/> 
resultMap>
4.2.1.1 id 标签

指定主键中的值,用于标识一个结果映射。

4.2.1.2 result 标签

指定非主键中的值,用于标识一个结果映射。

4.2.1.3 association 标签

通常用来映射一对一的关系。

4.2.1.4 collection 标签

通常用来映射一对多的关系。

4.2.2 select 标签

查询语句。

  • id:当前查询语句的唯一标识,该属性的值不能重复。
  • parameterType:指定参数类型。该属性是可选属性。因为 MyBatis 可以通过类型处理 器(TypeHandler)推断出具体传入语句的参数。
  • resultType:期望从这条语句中返回结果的类全名或别名。
  • resultMap:使用 resultMap 标签来处理结果集映射。
<select id="selectUser" parameterType="int" resultType="u"> 
	select * from users where userid = #{userid} 
select>
4.2.3 insert 标签

添加语句。

  • id:当前添加语句的唯一标识,该属性的值不能重复。
  • parameterType:指定参数类型,可以给定别名。该属性是可选属性。
<insert id="insertUser" parameterType="com.bjsxt.pojo.User">
	insert into users values(default ,#{username},#{usersex}) 
insert>
4.2.4 update 标签

更新语句。

  • id:当前更新语句的唯一标识,该属性的值不能重复。
  • parameterType:指定参数类型,可以给定别名。该属性是可选属性。
<update id="updateUser" parameterType="com.bjsxt.pojo.User"> 
	update users set username=#{username},usersex=#{usersex} where userid =#{userid} 
update>
4.2.5 delete 标签 删除语句。
  • id:当前删除语句的唯一标识,该属性的值不能重复。
  • parameterType:指定参数类型,可以给定别名。该属性是可选属性。
<delete id="deleteUser" parameterType="int"> 
	delete from users where userid = #{userid} 
delete>
4.2.6 sql 标签

可以用来定义可重用的 SQL 代码片段。通过标签引入该片段。

  • id:当前 SQL 片段的唯一标识,该属性的值不能重复。
<sql id="userColumns"> 
	userid,username,usersex 
sql>
<select id="selectUser" parameterType="int" resultType="u"> 
	select <include refid="userColumns"/> from users 
select>

5 Mybatis 的入门案例

5.1搭建环境

5.1.1 创建表

CREATE TABLE `users` ( 
	`userid` int(11) NOT NULL AUTO_INCREMENT, 
	`username` varchar(20) DEFAULT NULL, 
	`usersex` varchar(10) DEFAULT NULL, 
	PRIMARY KEY (`userid`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

5.1.2 添加 DTD 约束文件

在没有联网的情况下,如果让 dtd 约束继续起作用,并且出现标签提示,可以通过引入 本地 dtd 文件来实现。
下 载 dtd : 在 浏 览 器 中 输 入 dtd 的 网 络 地 址 即 可 实 现 下 载 。 比 如 : http://mybatis.org/dtd/mybatis-3-config.dtd
将下载的 dtd 拷贝到本地的一个目录下
Idea 操作路径:File—Settings—Languages & Frameworks
MyBatis实战【上】_第14张图片
其中 URI 复制 dtd 的网络地址即可。File 选择 dtd 文件在本地的地址。OK!

【注】:在 MyBatis 的核心 jar 包中就提供了 mybatis-3-config.dtd

5.1.3 创建项目

MyBatis实战【上】_第15张图片

5.1.4 添加 jar 包

MyBatis实战【上】_第16张图片
MyBatis实战【上】_第17张图片

5.1.5 创建实体

package com.bjsxt.pojo;

public class Users {
    private int userid;
    private String username;
    private String usersex;

    public int getUserid() {
        return userid;
    }

    public void setUserid(int userid) {
        this.userid = userid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUsersex() {
        return usersex;
    }

    public void setUsersex(String usersex) {
        this.usersex = usersex;
    }
}

5.1.6 创建 properties 文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/bjsxt
jdbc.username=root
jdbc.password=root

5.1.7 创建全局配置文件


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <properties resource="db.properties"/>

   
    <settings>
        <setting name="logImpl" value="SLF4J"/>
    settings>
    
    <typeAliases>
        <typeAlias type="com.bjsxt.pojo.Users" alias="u"/>
        <package name="com.bjsxt.pojo"/>
    typeAliases>
    
    <environments default="development">
        <environment id="development">
           
            <transactionManager type="JDBC">transactionManager>
           
            <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>
        environment>
    environments>

    
    <mappers>
       
        <mapper resource="com/bjsxt/mapper/UsersMapper.xml"/>
    mappers>

configuration>

5.1.8 创建映射配置文件


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.UserMapper">

mapper>

5.2查询数据

5.2.1 修改映射配置文件


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.UserMapper">

    
    <select id="selectUsersAll" resultType="com.bjsxt.pojo.Users">
         select * from users
    select>
  
mapper>

5.2.2 创建 UsersDao 接口

package com.bjsxt.dao;

import com.bjsxt.pojo.Users;

import java.io.IOException;
import java.util.List;
import java.util.Map;

public interface UsersDao {
    List<Users> selectUsersAll()throws IOException;
  
}

5.2.3 创建 UsersDao 接口实现类

package com.bjsxt.dao.impl;

import com.bjsxt.dao.UsersDao;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.cursor.Cursor;
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;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class UsersDaoImpl implements UsersDao {
    /**
     * 查询所有用户
     * @return
     */
    @Override
    public List<Users> selectUsersAll()throws IOException {
        //创建SqlSessionFactory对象
        InputStream inputStream = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = sqlSessionFacotry.openSession();
        //通过SqlSession对象下的API完成对数据库的操作
        List<Users> list = sqlSession.selectList("com.bjsxt.mapper.UserMapper.selectUsersAll");
        //关闭SqlSession对象
        sqlSession.close();
        return list;
    }
}

5.2.4 创建测试类

package com.bjsxt.test;

import com.bjsxt.dao.UsersDao;
import com.bjsxt.dao.impl.UsersDaoImpl;
import com.bjsxt.pojo.Users;

import java.io.IOException;
import java.util.List;

public class Test {
    public static void main(String[] args)throws IOException {
        UsersDao usersDao = new UsersDaoImpl();
        List<Users> list =  usersDao.selectUsersAll();
        for(Users users:list){
            System.out.println(users.getUserid()+"\t"+users.getUsername()+"\t"+users.getUsersex());
        }
    }
}

5.3根据用户 Id 查询数据


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.UserMapper">

    
    <select id="selectUsersAll" resultType="com.bjsxt.pojo.Users">
         select * from users
    select>
    
    <select id="selectUsersById" parameterType="int" resultType="users">
         select * from users where userid = #{suibian}
    select>
mapper>

5.3.1 修改映射配置文件

package com.bjsxt.dao;

import com.bjsxt.pojo.Users;

import java.io.IOException;
import java.util.List;
import java.util.Map;

public interface UsersDao {
    List<Users> selectUsersAll()throws IOException;
    Users selectUsersById(int userid)throws IOException;
}

5.3.3 修改 UsersDao 接口实现类

package com.bjsxt.dao.impl;

import com.bjsxt.dao.UsersDao;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.cursor.Cursor;
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;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class UsersDaoImpl implements UsersDao {
    /**
     * 查询所有用户
     * @return
     */
    @Override
    public List<Users> selectUsersAll()throws IOException {
        //创建SqlSessionFactory对象
        InputStream inputStream = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = sqlSessionFacotry.openSession();
        //通过SqlSession对象下的API完成对数据库的操作
        List<Users> list = sqlSession.selectList("com.bjsxt.mapper.UserMapper.selectUsersAll");
        //关闭SqlSession对象
        sqlSession.close();
        return list;
    }

    /**
     *  根据用户ID查询用户
     * @param userid
     * @return
     * @throws IOException
     */
    @Override
    public Users selectUsersById(int userid) throws IOException {
        //创建SqlSessionFactory对象
        InputStream inputStream = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = sqlSessionFacotry.openSession();
        Users users = sqlSession.selectOne("com.bjsxt.mapper.UserMapper.selectUsersById",userid);
        sqlSession.close();
        return users;
    }
}

5.3.4 修改测试类

package com.bjsxt.test;

import com.bjsxt.dao.UsersDao;
import com.bjsxt.dao.impl.UsersDaoImpl;
import com.bjsxt.pojo.Users;

import java.io.IOException;
import java.util.List;

public class Test {
    public static void main(String[] args)throws IOException {
        UsersDao usersDao = new UsersDaoImpl();
        /*List list =  usersDao.selectUsersAll();
        for(Users users:list){
            System.out.println(users.getUserid()+"\t"+users.getUsername()+"\t"+users.getUsersex());
        }*/
        Users users = usersDao.selectUsersById(1);
        System.out.println(users.getUserid()+"\t"+users.getUsername()+"\t"+users.getUsersex());
    }
}

5.4Mybatis 中的参数绑定

在映射配置文件中向 SQL 语句中绑定参数的语法结构为#{ }和${ }
#{ } 和 ${ }的区别:
#{ } 解析为一个 JDBC 预编译语句(PreparedStatement)的参数标记符占位符 。使 用该方式可避免 SQL 注入。
${ }仅仅为一个纯碎的 String 替换,在 Mybatis 的动态 SQL 解析阶段将会进行变量替 换。${ }在预编译之前已经被变量替换了,这会存在 SQL 注入问题。

5.5创建 Mybatis 的工具类

5.5.1 ThreadLocal 介绍

ThreadLocal 提供了线程内存储变量的能力,这些变量不同之处在于每一个线程读取的 变量是对应的互相独立的。通过getset 方法就可以得到当前线程对应的值。

5.5.2 使用 ThreadLocal 存储 SqlSession

如果多个 DML 操作属于一个事务,因为 commit()和 rollback()都是由 SqlSession 完成的, 所以必须保证使用一个 SqlSession。但是多个不同的 DML 操作可能在不同类的不同方法中, 每个方法中要单独的获取 SqlSession。比如商城下订单时,其实涉及商品库存变化、订单添 加、订单明细添加、付款、日志添加等多个 DML 操作,分布在不同类中。
如何在多个 DML 操作之间使用同一个 SqlSession 呢,可以使用 ThreadLocal 来存储。保 证一个线程中的操作使用的都是一个 SqlSession。
MyBatis实战【上】_第18张图片
在 Web 项目中用户的每次请求会启动一个新的线程,比如点击”结算”完成购物车结 算。在 Java 项目中每次启动 main()也会自动开启一个 main 线程

5.5.3 创建 Mybatis 工具类

package com.bjsxt.utils;

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 MybatisUtils {
    private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<>();
    private static SqlSessionFactory sqlSessionFactory = null;
    static{
        //创建SqlSessionFactory
        InputStream is = null;
        try{
            is = Resources.getResourceAsStream("mybatis-cfg.xml");
        }catch (IOException e){
            e.printStackTrace();
        }
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    }

    //获取SqlSession
    public static SqlSession getSqlSession(){
        SqlSession sqlSession = threadLocal.get();
        if(sqlSession == null){
            sqlSession = sqlSessionFactory.openSession();
            threadLocal.set(sqlSession);
        }
        return sqlSession;
    }

    //关闭SqlSession
    public static void closeSqlSession(){
        SqlSession sqlSession = threadLocal.get();
        if(sqlSession != null){
            sqlSession.close();
            threadLocal.set(null);
        }
    }
}

5.6完成 DML 操作

5.6.1 Mybatis 的事务提交方式

在 Mybatis 中事务提交方式默认为手动提交,这与 JDBC 是不同的。在 JDBC 中事务默认 提交方式为自动提交。
手动提交事务(默认)

SqlSession sqlSession = sqlSessionFacotry.openSession();

自动提交事务

SqlSession sqlSession = sqlSessionFacotry.openSession(true);

5.6.2 添加用户操作

5.6.2.1 修改映射配置文件

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.UserMapper">

    
    <select id="selectUsersAll" resultType="com.bjsxt.pojo.Users">
         select * from users
    select>
    
    <select id="selectUsersById" parameterType="int" resultType="users">
         select * from users where userid = #{suibian}
    select>

    
    <insert id="insertUsers" >
        insert into users value(default ,#{username},#{usersex})
    insert>
mapper>
5.6.2.2 修改 UsersDao 接口
package com.bjsxt.dao;

import com.bjsxt.pojo.Users;

import java.io.IOException;
import java.util.List;
import java.util.Map;

public interface UsersDao {
    List<Users> selectUsersAll()throws IOException;
    Users selectUsersById(int userid)throws IOException;
    void insertUsers(Users users);
}
5.6.2.3 修改 UsersDao 接口实现类
package com.bjsxt.dao.impl;

import com.bjsxt.dao.UsersDao;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.cursor.Cursor;
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;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class UsersDaoImpl implements UsersDao {
    /**
     * 查询所有用户
     * @return
     */
    @Override
    public List<Users> selectUsersAll()throws IOException {
        //创建SqlSessionFactory对象
        InputStream inputStream = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = sqlSessionFacotry.openSession();
        //通过SqlSession对象下的API完成对数据库的操作
        List<Users> list = sqlSession.selectList("com.bjsxt.mapper.UserMapper.selectUsersAll");
        //关闭SqlSession对象
        sqlSession.close();
        return list;
    }

    /**
     *  根据用户ID查询用户
     * @param userid
     * @return
     * @throws IOException
     */
    @Override
    public Users selectUsersById(int userid) throws IOException {
        //创建SqlSessionFactory对象
        InputStream inputStream = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = sqlSessionFacotry.openSession();
        Users users = sqlSession.selectOne("com.bjsxt.mapper.UserMapper.selectUsersById",userid);
        sqlSession.close();
        return users;
    }

    @Override
    public void insertUsers(Users users) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        sqlSession.insert("com.bjsxt.mapper.UserMapper.insertUsers", users);
    }
}
5.6.2.4 创建 UsersService 业务层接口
package com.bjsxt.service;

import com.bjsxt.pojo.Users;

import java.util.Map;

public interface UsersService {
    void addUsers(Users users);
}
5.6.2.5 创建 UsersService 业务层接口实现类
package com.bjsxt.service.impl;

import com.bjsxt.dao.UsersDao;
import com.bjsxt.dao.impl.UsersDaoImpl;
import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.Map;

public class UsersServiceImpl implements UsersService {
    /**
     * 添加用户
     * @param users
     */
    @Override
    public void addUsers(Users users) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UsersDao usersDao =  new UsersDaoImpl();
            usersDao.insertUsers(users);
            sqlSession.commit();
        }catch (Exception e){
            e.printStackTrace();
            sqlSession.rollback();
        }finally{
            MybatisUtils.closeSqlSession();
        }
    }
}
5.6.2.6 创建测试类
package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;

public class AddUserTest {
    public static void main(String[] args) {
        UsersService usersService = new UsersServiceImpl();
        Users users = new Users();
        users.setUsername("zhangsan");
        users.setUsersex("male");
        usersService.addUsers(users);
    }
}

5.6.3 更新用户操作

5.6.3.1 修改映射配置文件

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.UserMapper">

    
    <select id="selectUsersAll" resultType="com.bjsxt.pojo.Users">
         select * from users
    select>
    
    <select id="selectUsersById" parameterType="int" resultType="users">
         select * from users where userid = #{suibian}
    select>

    
    <insert id="insertUsers" >
        insert into users value(default ,#{username},#{usersex})
    insert>

    
    <select id="selectUserById2" resultType="com.bjsxt.pojo.Users">
        select * from users where userid = ${userid}
    select>
mapper>
5.6.3.2 修改 UsersDao 接口
package com.bjsxt.dao;

import com.bjsxt.pojo.Users;

import java.io.IOException;
import java.util.List;
import java.util.Map;

public interface UsersDao {
    List<Users> selectUsersAll()throws IOException;
    Users selectUsersById(int userid)throws IOException;
    void insertUsers(Users users);
    Users selectUsersById2(int userid);
    void updateUsersById(Users users);
}
5.6.3.3 修改 UsersDao 接口实现类
package com.bjsxt.dao.impl;

import com.bjsxt.dao.UsersDao;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.cursor.Cursor;
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;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class UsersDaoImpl implements UsersDao {
    /**
     * 查询所有用户
     * @return
     */
    @Override
    public List<Users> selectUsersAll()throws IOException {
        //创建SqlSessionFactory对象
        InputStream inputStream = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = sqlSessionFacotry.openSession();
        //通过SqlSession对象下的API完成对数据库的操作
        List<Users> list = sqlSession.selectList("com.bjsxt.mapper.UserMapper.selectUsersAll");
        //关闭SqlSession对象
        sqlSession.close();
        return list;
    }

    /**
     *  根据用户ID查询用户
     * @param userid
     * @return
     * @throws IOException
     */
    @Override
    public Users selectUsersById(int userid) throws IOException {
        //创建SqlSessionFactory对象
        InputStream inputStream = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = sqlSessionFacotry.openSession();
        Users users = sqlSession.selectOne("com.bjsxt.mapper.UserMapper.selectUsersById",userid);
        sqlSession.close();
        return users;
    }

    @Override
    public void insertUsers(Users users) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        sqlSession.insert("com.bjsxt.mapper.UserMapper.insertUsers", users);
    }

    //预更新用户的查询
    @Override
    public Users selectUsersById2(int userid) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        Users users =  sqlSession.selectOne("com.bjsxt.mapper.UserMapper.selectUserById2",userid);
        return users;
    }

    //更新用户
    @Override
    public void updateUsersById(Users users) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        sqlSession.update("com.bjsxt.mapper.UserMapper.updateUsersById", users);
    }
}
5.6.3.4 修改 UsersService 接口
package com.bjsxt.service;

import com.bjsxt.pojo.Users;

import java.util.Map;

public interface UsersService {
    void addUsers(Users users);
    Users preUpdateUsers(int userid);
    void modifyUsers(Users users);
}
5.6.3.5 修改 UsersService 接口实现类
package com.bjsxt.service.impl;

import com.bjsxt.dao.UsersDao;
import com.bjsxt.dao.impl.UsersDaoImpl;
import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.Map;

public class UsersServiceImpl implements UsersService {
    /**
     * 添加用户
     * @param users
     */
    @Override
    public void addUsers(Users users) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UsersDao usersDao =  new UsersDaoImpl();
            usersDao.insertUsers(users);
            sqlSession.commit();
        }catch (Exception e){
            e.printStackTrace();
            sqlSession.rollback();
        }finally{
            MybatisUtils.closeSqlSession();
        }
    }

    @Override
    public Users preUpdateUsers(int userid) {
        Users users = null;
        try{
            SqlSession sqlSession = MybatisUtils.getSqlSession();
           UsersDao usersDao = new UsersDaoImpl();
           users = usersDao.selectUsersById2(userid);
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            MybatisUtils.closeSqlSession();
        }
        return users;
    }

    @Override
    public void modifyUsers(Users users) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UsersDao usersDao = new UsersDaoImpl();
            usersDao.updateUsersById(users);
            sqlSession.commit();
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
        }finally {
            MybatisUtils.closeSqlSession();
        }
    }
}
5.6.3.6 创建测试类
package com.bjsxt.test;

import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;

public class UpdateUsersTest {
    public static void main(String[] args) {
        UsersService usersService = new UsersServiceImpl();
        Users users = usersService.preUpdateUsers(2);
        System.out.println(users.getUserid());
        users.setUsername("OLDLU");
        users.setUsersex("MALE");
        usersService.modifyUsers(users);
    }
}

5.6.4 删除用户操作

5.6.4.1 修改映射配置文件

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.UserMapper">

    
    <select id="selectUsersAll" resultType="com.bjsxt.pojo.Users">
         select * from users
    select>
    
    <select id="selectUsersById" parameterType="int" resultType="users">
         select * from users where userid = #{suibian}
    select>

    
    <insert id="insertUsers" >
        insert into users value(default ,#{username},#{usersex})
    insert>

    
    <select id="selectUserById2" resultType="com.bjsxt.pojo.Users">
        select * from users where userid = ${userid}
    select>
    
    <update id="updateUsersById" >
        update users set username = #{username},usersex=#{usersex} where userid = #{userid}
    update>
   
    <delete id="deleteUsersById">
        delete from users where userid = #{userid}
    delete>
mapper>
5.6.4.2 修改 UsersDao 接口
package com.bjsxt.dao;

import com.bjsxt.pojo.Users;

import java.io.IOException;
import java.util.List;
import java.util.Map;

public interface UsersDao {
    List<Users> selectUsersAll()throws IOException;
    Users selectUsersById(int userid)throws IOException;
    void insertUsers(Users users);
    Users selectUsersById2(int userid);
    void updateUsersById(Users users);
    void deleteUsersById(int userid);
}
5.6.4.3 修改 UsersDao 接口实现类
package com.bjsxt.dao.impl;

import com.bjsxt.dao.UsersDao;
import com.bjsxt.pojo.Users;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.cursor.Cursor;
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;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class UsersDaoImpl implements UsersDao {
    /**
     * 查询所有用户
     * @return
     */
    @Override
    public List<Users> selectUsersAll()throws IOException {
        //创建SqlSessionFactory对象
        InputStream inputStream = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = sqlSessionFacotry.openSession();
        //通过SqlSession对象下的API完成对数据库的操作
        List<Users> list = sqlSession.selectList("com.bjsxt.mapper.UserMapper.selectUsersAll");
        //关闭SqlSession对象
        sqlSession.close();
        return list;
    }

    /**
     *  根据用户ID查询用户
     * @param userid
     * @return
     * @throws IOException
     */
    @Override
    public Users selectUsersById(int userid) throws IOException {
        //创建SqlSessionFactory对象
        InputStream inputStream = Resources.getResourceAsStream("mybatis-cfg.xml");
        SqlSessionFactory sqlSessionFacotry = new SqlSessionFactoryBuilder().build(inputStream);
        //获取SqlSession对象
        SqlSession sqlSession = sqlSessionFacotry.openSession();
        Users users = sqlSession.selectOne("com.bjsxt.mapper.UserMapper.selectUsersById",userid);
        sqlSession.close();
        return users;
    }

    @Override
    public void insertUsers(Users users) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        sqlSession.insert("com.bjsxt.mapper.UserMapper.insertUsers", users);
    }

    //预更新用户的查询
    @Override
    public Users selectUsersById2(int userid) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        Users users =  sqlSession.selectOne("com.bjsxt.mapper.UserMapper.selectUserById2",userid);
        return users;
    }

    //更新用户
    @Override
    public void updateUsersById(Users users) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        sqlSession.update("com.bjsxt.mapper.UserMapper.updateUsersById", users);
    }

    @Override
    public void deleteUsersById(int userid) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        final int delete = sqlSession.delete("com.bjsxt.mapper.UserMapper.deleteUsersById", userid);
    }
 }
5.6.4.4 修改 UsersService 接口
package com.bjsxt.service;

import com.bjsxt.pojo.Users;

import java.util.Map;

public interface UsersService {
    void addUsers(Users users);
    Users preUpdateUsers(int userid);
    void modifyUsers(Users users);
    void dropUsersById(int userid);
}
5.6.4.5 修改 UsersService 接口实现类
package com.bjsxt.service.impl;

import com.bjsxt.dao.UsersDao;
import com.bjsxt.dao.impl.UsersDaoImpl;
import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
import com.bjsxt.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.Map;

public class UsersServiceImpl implements UsersService {
    /**
     * 添加用户
     * @param users
     */
    @Override
    public void addUsers(Users users) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UsersDao usersDao =  new UsersDaoImpl();
            usersDao.insertUsers(users);
            sqlSession.commit();
        }catch (Exception e){
            e.printStackTrace();
            sqlSession.rollback();
        }finally{
            MybatisUtils.closeSqlSession();
        }
    }

    @Override
    public Users preUpdateUsers(int userid) {
        Users users = null;
        try{
            SqlSession sqlSession = MybatisUtils.getSqlSession();
           UsersDao usersDao = new UsersDaoImpl();
           users = usersDao.selectUsersById2(userid);
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            MybatisUtils.closeSqlSession();
        }
        return users;
    }

    @Override
    public void modifyUsers(Users users) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UsersDao usersDao = new UsersDaoImpl();
            usersDao.updateUsersById(users);
            sqlSession.commit();
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
        }finally {
            MybatisUtils.closeSqlSession();
        }
    }

    @Override
    public void dropUsersById(int userid) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UsersDao usersDao = new UsersDaoImpl();
            usersDao.deleteUsersById(userid);
            sqlSession.commit();
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
        }finally{
            MybatisUtils.closeSqlSession();
        }
    }
}
5.6.4.6 创建测试类
package com.bjsxt.test;

import com.bjsxt.service.UsersService;
import com.bjsxt.service.impl.UsersServiceImpl;

public class DeleteUsersTest {
    public static void main(String[] args) {
        UsersService usersService = new UsersServiceImpl();
        usersService.dropUsersById(3);
    }
}

三、 Java 日志处理框架

1 常用的日志处理框架

对于一个应用程序来说日志记录是必不可少的一部分。线上问题追踪,错误排查,基于 日志的业务逻辑统计分析等都离不日志。
日志的管理是系统很重要的一部分,千万不可忽略其重要性。完整的日志将会在系统维 护中起着异常重要的作用。
在 Java 领域存在多种日志框架,目前常用的日志框架包括 Log4j,Log4j2,Commons Logging,Slf4j,Logback,Jul。

2 Log4j 简介

Log4j: Log For Java(Java 的日志) 是 Apache 提供的一个开源的 Java 主流的日志框架。

3 Log4j 的日志级别

Log4j 定义了 8 个日志级别(除去 OFF 和 ALL,可以说分为 6 个级别),优先级从高到 低依次为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL。

在 Log4j 中建议只使用 DEBUG、INFO、WARN、ERROR 四个日志级别。

  • ALL 最低等级的,用于打开所有日志记录。
  • TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12,很低的 日志级别,一般不会使用。
  • DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打 印一些运行信息。
  • INFO 消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重 要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避 免打印过多的日志。
  • WARN 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员的一 些提示。
  • ERROR 指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息, 如果不想输出太多的日志,可以使用这个级别。
  • FATAL 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错 误,这种级别你可以直接停止程序了。
  • OFF 最高等级的,用于关闭所有日志记录。

4 Log4j 的使用

4.1Log4j 配置文件详解

4.1.1 Log4j 配置文件名

log4j 配置文件名:log4j.properties
Log4j 配值文件存放位置:项目的 src 的根目录中

4.1.2 配置根 Logger

log4j.rootLogger = [level],appenderName,appenderName2,...

level 是日志记录的优先级,优先级从低到高分别是 DEBUG,INFO,WARN,ERROR。通过在 这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关,比如在这里定义了 INFO 级别,则应用程序中所有 DEBUG 级别的日志信息将不被打印出来

appenderName 就是指定日志信息输出到哪个地方。可同时指定多个输出目的地。

4.1.3 Log4j 中的 appender

  • org.apache.log4j.ConsoleAppender(输出到控制台)
  • org.apache.log4j.FileAppender(输出到文件)
  • org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
  • org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
  • org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
  • org.apache.log4j.jdbc.JDBCAppender(将日志信息添加数据库中)

4.1.4 向控制台输出的 appender

### appender.console 输出到控制台 ### 
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout 
log4j.appender.console.layout.ConversionPattern=<%d> %5p (%F:%L) [%t] (%c) - %m%n 
log4j.appender.console.Target=System.out

4.1.5 向文件输出的 appender

### appender.logfile 输出到日志文件 ### 
log4j.appender.logfile=org.apache.log4j.RollingFileAppender 
log4j.appender.logfile.File=SysLog.log 
log4j.appender.logfile.MaxFileSize=500KB 
log4j.appender.logfile.MaxBackupIndex=7 
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 
log4j.appender.logfile.layout.ConversionPattern=<%d> %p (%F:%L) [%t] %c - %m%n

4.1.6 向数据库输出的 appender

log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender 
log4j.appender.logDB.layout=org.apache.log4j.PatternLayout 
log4j.appender.logDB.Driver=com.mysql.jdbc.Driver 
log4j.appender.logDB.URL=jdbc:mysql://localhost:3306/bjsxt 
log4j.appender.logDB.User=root 
log4j.appender.logDB.Password=root 
log4j.appender.logDB.Sql=INSERT INTO 
logs(project_name,create_date,level,category,file_name,thread_name,line,all_ category,message)values('logDemo','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','% t','%L','%l','%m')

4.1.7 通过包名控制日志输出级别

log4j.logger.org.apache=FATAL 
log4j.logger.org.apache.commons=ERROR 
log4j.logger.org.springframework=ERROR 
log4j.logger.com.bjsxt=ERROR

4.1.8 Log4j 的输出格式

Log4J 采用类似 C 语言中的 printf 函数的打印格式格式化日志信息,打印参数如下:

  • %m 输出代码中指定的消息
  • %p 输出优先级,即 DEBUG,INFO,WARN,ERROR,FATAL
  • %r 输出自应用启动到输出该 log 信息耗费的毫秒数
  • %c 输出所属的类目,通常就是所在类的全名
  • %t 输出产生该日志事件的线程名
  • %n 输出一个回车换行符,Windows 平台为“\r\n”,Unix 平台为“\n”
  • %d 输出日志时间点的日期或时间,默认格式为 ISO8601,也可以在其后指定格式
    如:%d{yyyy 年 MM 月 dd 日 HH:mm:ss,SSS},输出类似:2020 年 05 月 01 日 22:10:28,921
  • %l输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数 如: Testlog.main(TestLog.java:10)
  • %F 输出日志消息产生时所在的文件名称
  • %L 输出代码中的行号
  • %x 输出和当前线程相关联的 NDC(嵌套诊断环境),像 java servlets 多客户多线程的应用 中
  • %%输出一个"%"字符

可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。 如:

  • %5c: 输出 category 名称,最小宽度是 5,category<5,默认的情况下右对齐
  • %-5c:输出 category 名称,最小宽度是 5,category<5,"-"号指定左对齐,会有空格
  • %.5c:输出 category 名称,最大宽度是 5,category>5,就会将左边多出的字符截掉,<5 不会有空格
  • %20.30c:category 名称<20 补空格,并且右对齐,>30 字符,就从左边交远销出的字符截掉

4.2Log4j 的使用方式

4.2.1 Log4j.jar

添加 jar 包:log4j.jar
添加配置文件:log4j.properties
通过 Log4j 的 API 完成日志

import org.apache.log4j.Logger; 
public class LogDemo { 
	private final static Logger logger = Logger.getLogger(LogDemo.class); 
}

4.2.2 commons-logging + log4j

commons-logging 是 Apache 的 Commons 项目中提供的一个高层的日志框架,是门面模 式的典型应用。commons-logging 本身没有实现真正的日志能力。它可以挂接不同的日志系 统,默认情况下,Commons Loggin 自动搜索并使用 Log4j,如果没有找到 Log4j,再使用JDK。

Logging。
log4j.jar
commons-loggin.jar
项目中常用使用

import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
public class LogDemo { 
	private static final Log logger = LogFactory.getLog(LogDemo.class); 
	}

4.2.3 slf4j-api + slf4j-log4j + log4j

SLF4J 的全称是 Simple Logging Facade for Java,即简单日志门面应用。SLF4J 并不是具体 的日志框架,而是作为一个简单门面服务于各类日志框架,如 java.util.logging, logback 和 log4j。
slf4j-api.jar
slf4j-log4j.jar
log4j.jar

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
public class LogDemo { 
	private static final Logger logger = LoggerFactory.getLogger(LogDemo.class); 
}

四、 Mybatis 配置的完善

1 Mybatis 的日志管理

Mybatis 的内置日志工厂(LogFactory)提供日志处理功能,内置日志工厂将日志交 给以下其中一种工具作代理:

  • SLF4J
  • Apache Commons Logging
  • Log4j2
  • Log4j
  • JDK logging
  • NO_LOGGING
    MyBatis 内置日志工厂基于运行时自省机制选择合适的日志工具。它会使用第一个查 找得到的工具(按上文列举的顺序查找)。如果一个都未找到,日志功能就会被禁用。也就是说在项目中把日志工具环境配置出来后,不用再 MyBatis 进行配置就可以让日志生效。
    MyBatis实战【上】_第19张图片

指定 SLF4J 作为日志处理器

<settings> 
	<setting name="logImpl" value="SLF4J"/> 
settings>

2 使用别名 alias

Mybatis 中的别名配置它只和 XML 配置有关, 只用来减少类完全限定名的多余部分。注 意:别名都是大小写不敏感的。
在配置文件中为类的完整路径定义别名,可以采用两种方式

2.1方式一

使用 typeAlias 指定单个类的别名,在全局配置文件中配置,【注意】:直接放到setting标签之后


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <properties resource="db.properties"/>

   
    <settings>
        <setting name="logImpl" value="SLF4J"/>
    settings>
    
    <typeAliases>
        <typeAlias type="com.bjsxt.pojo.Users" alias="u"/>
        <package name="com.bjsxt.pojo"/>
    typeAliases>
    
    <environments default="development">
        <environment id="development">
           
            <transactionManager type="JDBC">transactionManager>
           
            <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>
        environment>
    environments>

    
    <mappers>
       
        <mapper resource="com/bjsxt/mapper/UsersMapper.xml"/>
    mappers>


configuration>
<select id="selectUsersById" parameterType="int" resultType="u"> 
	select * from users where userid = #{suibian} 
select>

2.2方式二

使用 package 指定某个包下所有类的默认别名

<typeAliases> 
	<package name="com.bjsxt.pojo"/> 
typeAliases>

引入别名后的映射文件