MyBatis
前言
1、需要的环境
- JDK 1.8
- mysql 8.0
- maven 3.8.1
- IDEA
2、回顾相关技术
- JDBC
- Mysql
- Java基础
- Maven
- Junit
1、简介
1.1、什么是 MyBatis?
- MyBatis 是一款优秀的持久层框架。
- 它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
- MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis。
- 2013年11月迁移到Github
1.2、如何获得MyBatis?
-
maven仓库中获取
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> -
去GitHub上搜索: github.com/search?q=My…
- 中文文档: mybatis.org/mybatis-3/z…
1.3、 持久化
1.3.1、数据持久化
- 定义: 持久化就是将程序的数据在瞬时状态和持久状态转化的过程
- 内存特性: 断电即失
- 持久化手段: 数据库, io文件持久化......
- 生活实例: 冷藏, 罐头
1.3.2、为什么要持久化
- 重要数据要保证不能丢失
- 内存太贵
1.4、 持久层
Dao层, Service层, Controller层
- 完成持久化工作的模块
- 层界限十分明显
1.5、 为什么需要MyBatis
- 帮助开发者将数据存入到数据库中
- 方便, 简单, 易上手
- 传统的JDDBC代码太复杂, 它可以简化, 约束于框架, 实现自动化
- 特点:
- 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
- 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。 通过sql语句可以满足操作数据库的所有需求。
- 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的orm字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持编写动态sql。
2、第一个Mybatis程序
思路: 搭建环境==>导入Mybaits==>编写代码==>测试
2.1、搭建环境
- 搭建数据库:
CREATE DATABASE `mybatis`;
USE `mybatis-demo`;
CREATE TABLE `USER` (
`id` INT(20) NOT NULL PRIMARY KEY,
`username` VARCHAR(30) DEFAULT NULL,
`password` VARCHAR(30) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `USER` (`id`,`username`,`password`) VALUES
(1,"子苏","1234"),
(2,"admin","0000"),
(3,"muser","3571")
-
新建项目
- 新建一个普通的maven项目 (无模板)
- 作为父工程, 删除src
- 导入依赖
<!-- mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.25</version> </dependency> <!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency>
2.2、创建一个模块 (子module)
2.2.1、编写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">
<!--mybatis的核心配置文件-->
<configuration>
<environments default="development">
<environment id="development">
<!--事物管理类型JDBC-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--注意新版的mysql有cj这个包-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<!--安全连接,编码,时区-->
<property name="url" value="jdbc:mysql://localhost:3306?mybatis&useSSl=true&userUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
2.2.2、编写mybatis工具类
public class MybatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static{
try {
//使用mybatis第一步, 获取SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//SqlSession完全包含了面向数据库执行SQL命令所需的所有方法
public SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
2.3、编写代码
2.3.1、实体类
public class User {
private int id;
private String username;
private String password;
public User() {
}
public User(int id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
2.3.2、Dao接口
public interface UserDao {
public List<User> getUsers();
}
2.3.3、接口实现类
mybatis是用xml来代替dao接口的实现类
<?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.sama.dao.UserDao">
<!--查询语句-->
<select id="getUsers" resultType="com.sama.pojo.User">
select * from mybatis.user
</select>
</mapper>
2.4、测试
2.4.1、编写测试类并测试
public class UserDaoTest {
@Test
public void test(){
//1.获取SqlSession对象
SqlSession sqlSession = MybatisUtil.getSqlSession();
//2.获取UserDao对象
//2.1方式一, 最新推荐
UserDao userDao = sqlSession.getMapper(UserDao.class);
//2.2方式二, 这是原来的方法不建议使用
//List<User> users =sqlSession.selectList("com.sama.dao.UserDao.getUsers");
//3.执行查询方法
List<User> users = userDao.getUsers();
//4.看查询结果
for (User user : users) {
System.out.println(user);
}
//5.关闭SqlSession
sqlSession.close();;
}
}
2.4.2、错误
错误一
- 这是很容易犯的绑定错误: UserDao未在Mapper注册
- MapperRegistry是什么? 详见此文4.2
- 每一个Mapper.xml都需要在Mybatis核心配置文件中注册
错误二
- maven常见错误, 资源过滤问题, 在maven笔记可以找到
- maven由于它的约定大于配置, 可能会出现我们写的配置文件, 无法被导出或生效的问题
错误三
- 这是mybaits的Mapper.xml的文件头错误
<?xml version="1.0" encoding="UTF-8" ?>
-
具体原因: IDEA中写MyBatis的xml配置文件编译报错的坑
-
在整体项目的字符集设置中把在idea中新建的文件字符集默认为GBK形式了,所以所有的新建文件都会以GBK字符格式对中文字符进行转义,就会导致错误,可能是这两个编码格式对于某些特别中文的解码规则不同,有时可以互相错误使用,但是有时不可以,尤其是在写xml配置文件时。
-
又由于我的xml配置文件是这样写的,因为我以为已经配置好了idea的字符格式为UTF-8,但是我忘记了上次我只是在项目中配置的,却没有在idea全局中配置,所有导致今天误入了这个坑中。如果硬用GBK字符编码的话,这边encoding改为GBK也就可以了!
2.4.3、修改
- 在mybatis-config.xml中注册
<mappers>
<mapper resource="com/sam/dao/UserMapper.xml"/>
</mappers><mappers>
<mapper resource="com/sam/dao/UserMapper.xml"/>
</mappers>
- 在pom.xml文件加入build配置
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
-
两种修改方法, 推荐第二种一劳永逸
- 把xml文件头UTF-8改成UTF8
<?xml version="1.0" encoding="UTF8" ?>- 在idea全局中配置编码格式
2.4.4、错误总结
可能会出现以下错误
- 配置文件没有注册
- 绑定接口错误
- 方法名不对
- 返回类型不对
- Maven导出资源问题
3、增删改查
3.1、select
选择, 查询语句
- id: 就是对应的namespace中的方法名
- resultType: Sql语句执行的返回值
- parameterType: 参数类型
- 编写接口
public User getUserById(int id);
- 编写对应接口的映射文件mapper的sql语句
<!--查询语句-->
<select id="getUsers" resultType="com.sama.pojo.User">
select * from mybatis.user
</select>
3.测试
@Test
public void getUserById(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = userDao.getUserById(1);
System.out.println(user);
//close
sqlSession.close();
}
3.2、insert
- 编写接口
public int addUser(User user);
- 编写对应接口的映射文件mapper的sql语句
<!--对象中的属性,可以直接取出来-->
<insert id="addUser" parameterType="com.sama.pojo.User">
insert into mybatis.user (id,username,password) values (#{id},#{username},#{password})
</insert>
3.测试
@Test
public void addUser(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
int result = userDao.addUser(new User(4, "公子苏", "jjjj"));
if(result>0){
System.out.println("操作成功");
}
//提交事务
sqlSession.commit();
sqlSession.close();
}
3.3、update
sql语句
<update id="updateUser" parameterType="com.sama.pojo.User">
update mybatis.user set username=#{username}, password=#{password} where id=#{id}
</update>
3.4、delete
sql语句
<delete id="deleteUserById" parameterType="int">
delete from mybatis.user where id=#{id}
</delete>
3.5、注意点
- 注意! 增删改需要提交事务
- 注意! SqlSession要记得及时关闭
- 注意! resource绑定mapper需要路径"/", 不是"."
3.6、万能map
增加或修改, 参数可以不用对象用map
- xml的参数类型就直接是map
- 不用修改的字段, 可以在sql省略
- 字段对应的是key
dao接口
public int updateUserForMap(Map<String,Object> map);
sql语句
<update id="updateUser" parameterType="map">
update mybatis.user set username=#{keyUsername} where id=#{id}
</update>
测试
@Test
public void updateUserForMap(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
Map<String,Object> map = new HashMap<>();
map.put("keyId",3);
map.put("keyName","map无敌");
int result = userDao.updateUserForMap(map);
if(result>0){
System.out.println("操作成功");
}
sqlSession.commit();
sqlSession.close();
}
3.7、模糊查询
- java代码执行的时候, 传递通配符% %
List<User> users = userDao.getUsers("%李%");
- 在sql拼接中使用通配符
select * from mybatis.user where name like "%"#{value}"%"
4、mybatis核心配置解析
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
配置文档的顶层结构如下:
- configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
4.1、环境配置(environments)
MyBatis 可以配置成适应多种环境, 开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射
尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
4.1.1、注意一些关键点
- 默认使用的环境 ID(比如:default="development")。
- 每个 environment 元素定义的环境 ID(比如:id="development")。
- 事务管理器的配置(比如:type="JDBC")。
- 数据源的配置(比如:type="POOLED")。 默认环境和环境 ID 顾名思义。 环境可以随意命名,但务必保证默认的环境 ID 要匹配其中一个环境 ID。
4.1.2、事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
- JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
- MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。例如:
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
4.1.3、数据源(dataSource)
- dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
- 大多数 MyBatis 应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。
- 有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]")
4.2、属性
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。
- 用properties的子元素配置
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="root"/>
<property name="password" value="1234"/>
</properties>
<configuration>
<environments default="development">
<environment id="development">
<!--事物管理类型JDBC-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
</configuration>
2.用properties文件配置
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306?mybatis&useSSl=true&userUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username=root
password=1234
<properties resource="db.properties">
</properties>
<configuration>
<environments default="development">
<environment id="development">
<!--事物管理类型JDBC-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
</configuration>
在xml里调用属性用${key}
4.3、设置
| 设置名 | 描述 | 有效值 | 默认值 |
|---|---|---|---|
| cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true / false | true |
| lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 | true / false | false |
| mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | true / false | false |
| logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J / LOG4J / LOG4J2 / ... | 未设置 |
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
4.4、类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
- 类别名注解方式
@Alias("User")
public class User {
...
}
- 类别名XML 配置方式
<typeAliases>
<typeAlias alias="User" type="com.sama.pojo.User"/>
</typeAliases>
- 包别名XML 配置方式: MyBatis 会在包名下面搜索需要的 Java Bean
<typeAliases>
<package name="com.sama.pojo"/>
</typeAliases>
4.5、映射器(mappers)
MapperRegistry: 注册绑定要实现接口对应的映射mapper文件
有四种实现方式:
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
注意的是
- 第二种方式完全限定资源定位符(URL)一般不会使用
- 第三, 四种方式要一定的条件才能使用
- 接口和映射文件要在同一包下
- 接口和映射文件的名字要一致
- 推荐使用第一种
4.6、mapper映射配置文件里的名词
命名空间 (namespace)
- 绑定对应的要实现Dao接口
- 命名空间的作用有两个
- 一个是利用更长的全限定名来将不同的语句隔离开来,
- 同时也实现了你上面见到的接口绑定。
- 如下所示, namespace
<!--namespace: 绑定一个对应的Dao/Mapper接口--> <mapper namespace="com.sama.dao.UserDao"> <!--查询语句--> <select id="getUsers" resultType="com.sama.pojo.User"> select * from mybatis.user </select> </mapper>
4.7、作用域(Scope)和生命周期
对象生命周期和依赖注入框架
依赖注入框架可以创建线程安全的、基于事务的 SqlSession 和映射器,并将它们直接注入到你的 bean 中,因此可以直接忽略它们的生命周期
4.7.1、SqlSessionFactoryBuilder
- 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。
- 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
- 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。
4.7.2、SqlSessionFactory
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
- 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。
- 因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
4.7.3、SqlSession
- 每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
- 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。
- 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。
- 下面的示例就是一个确保 SqlSession 关闭的标准模式:
try (SqlSession session = sqlSessionFactory.openSession()) { // 你的应用逻辑代码 } - 在所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭。
4.7.4、映射器实例
- 映射器是一些绑定映射语句的接口。映射器接口的实例是从SqlSession中获得的。
- 虽然从技术层面上来讲,任何映射器实例的最大作用域与请求它们的 SqlSession 相同。但方法作用域才是映射器实例的最合适的作用域。 也就是说,映射器实例应该在调用它们的方法中被获取,使用完毕之后即可丢弃。
- 映射器实例并不需要被显式地关闭。尽管在整个请求作用域保留映射器实例不会有什么问题,但是你很快会发现,在这个作用域上管理太多像 SqlSession 的资源会让你忙不过来。
- 因此,最好将映射器放在方法作用域内。就像下面的例子一样:
try (SqlSession session = sqlSessionFactory.openSession()) { BlogMapper mapper = session.getMapper(BlogMapper.class); // 你的应用逻辑代码 }
一个CRUD操作的执行流程
SqlSessionFactory与SqlSession以及Mapper关系
这里的每一个Mapper, 就代表一个具体的业务
5、结果映射 (resultMap)
resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来
5.1、当属性名和字段名不一致
- 将sql的字段改成别名
<select id="selectUsers" resultType="User">
select
user_id as "id",
user_name as "userName",
hashed_password as "hashedPassword"
from some_table
where id = #{id}
</select>
- 使用resultMap
- 配置的resultMap
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
- sql语句
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
5.2、高级结果映射
MyBatis 创建时的一个思想是:数据库不可能永远是你所想或所需的那个样子。我们希望每个数据库都具备良好的第三范式或 BCNF 范式,可惜它们并不都是那样
结果映射(resultMap)
- constructor - 用于在实例化类时,注入结果到构造方法中
- idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
- arg - 将被注入到构造方法的一个普通结果
- id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
- result – 注入到字段或 JavaBean 属性的普通结果
- association – 一个复杂类型的关联;许多结果将包装成这种类型
- 嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用
- collection – 一个复杂类型的集合
- 嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用
- discriminator – 使用结果值来决定使用哪个 resultMap
- case – 基于某些值的结果映射
-
嵌套结果映射 – case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射
-
- case – 基于某些值的结果映射
6、日志
6.1、日志工厂
如果一个数据库操作,出现了异常。排错的时候,日志是最好的助手。没日志前使用的是sout、debug, 现在可以使用日志工厂实现
但是在mybatis中具体使用哪一个日志实现,在设置中设定。
| 设置名 | 描述 | 有效值 | 默认值 |
|---|---|---|---|
| logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | LOG4J / STDOUT_LOGGING / ... | 未设置 |
可选的值
- SLF4J
- LOG4J 掌握
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING 掌握
- NO_LOGGING
<settings>
<!--标准的日志工厂实现-->
<setting name="logImpl" value="LOG4J"/>
</settings>
注意 名字和值不可以写错,多一个空格都不可以。必须和官网一模一样!
- 这是没加日志控制台输出
- 使用"STDOUT_LOGGING"日志
6.2、Log4j
什么是Log4j
- Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等
- 我们也可以控制每一条日志的输出格式
- 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
- 这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
使用Log4j
- 导包
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
- 在Mybatis配置中配置日志实现
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
- 在CLASSPATH下建立log4j.properties (放到resources下就好了)
#配置根Logger
log4j.rootLogger = [ level ] , appenderName1 , appenderName2 , …
#配置日志信息输出目的地Appender
log4j.appender.appenderName = fully.qualified.name.of.appender.class
log4j.appender.appenderName.option1 = value1
…
log4j.appender.appenderName.optionN = valueN
#配置日志信息的格式(布局)
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1 = value1
…
log4j.appender.appenderName.layout.optionN = valueN
### set log levels ###
log4j.rootLogger = debug , stdout , D , E
### 输出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n
### 输出到日志文件 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 保存异常信息到单独文件 ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
-
日志对象,参数为当前类的class
static Logger logger = Logger.getLogger(UserDaoTest.class); -
日志级别
@Test
public void log4jTest() {
logger.info("info:进入了log4jTest");
logger.debug("debug:进入了log4jTest");
logger.error("error:进入了log4jTest");
}
- 格式解释
- log4j日志输出格式一览:
- %c 输出日志信息所属的类的全名
- %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在背后指定格式,比如:%d{yyy-MM-dd HH:mm:ss},输出类似于2020-02-01-17:17:16
- %f 输出日志信息所属类的类名
- %l 输出日志事件的发生未知,即输出日志信息的语句处于它所在的类的第几行
- %m 输出代码中指定的信息,如log(message)中的message
- %n 输出一个回车换行符,Windows平台为“rn”,Unix平台为‘n’
- %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL。如果是调用debug()输出的,则为DEBUG,一次类推
- %r 输出自应用启动到输出该日志信息所耗费的毫秒数
- %t 输出产生该日事件的线程名
所以%5p%t-%m%n就表示: 宽度为5的优先等级 线程名称(文件名:行号)-信息 回车换行
7、分页
使用limit分页
select * from user limit startIndex,pageSize;
select * from user limit n; #[0,n]