MyBatis 的 GitHub 地址:https://github.com/mybatis
具体链接地址:
MyBatis 下载:https://github.com/mybatis/mybatis-3
MyBatis 文档:https://mybatis.org/mybatis-3
其他链接地址:
MyBatis 中文文档:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html
MyBatis-Spring 官方中文文档:https://mybatis.org/spring/zh/index.html
MyBatis 是一个开源的数据持久层框架。它内部封装了 JDBC(Java database connectivity)访问数据库的操作,支持普通的 SQL(structured query language,结构化查询语言) 查询、存储过程和高级映射,几乎消除了所有的 JDBC 代码和参数的手工设置以及结果集的检索。
MyBatis 作为持久层框架,其主要思想是将程序中的大量 SQL 语句剥离出来,配置在配置文件中,实现 SQL 的灵活配置。这样做能将 SQL 与程序代码分离,可以在不修改程序代码的情况下,直接在配置文件中修改 SQL。
MyBatis 的前身是 iBatis,是 Apache 的一个开源项目。2010 年 6 月这个项目由 Apache Software Foundation 迁移到了Google Code。随着开发团队转投Google Code旗下, iBatis3.x 正式更名为 MyBatis。代码于2013年11月迁移到 Github。
iBatis一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。 iBatis提供的持久层框架包括SQL Maps和DAO(data access objects)。
1、MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。
2、MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
3、MyBatis 可以使用简单的 XML 或注解用于配置和原始映射,将接口和Java的POJO(Plain Ordinary Java Object,普通的Java对象)映射成数据库中的记录。
4、MyBatis 是一个半自动的 ORM(Object Relational Mapping)框架。
JDBC
1、SQL 夹杂在Java代码中耦合度高,导致硬编码内伤。
2、维护不易且实际开发需求中 SQL 有变化,频繁修改的情况多见。
3、代码冗长,开发效率低。
MyBatis
1、轻量级,性能出色。
2、SQL 和 Java 编码分开,功能边界清晰。Java 代码专注业务、SQL 语句专注数据。
MyBatis 相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL 写在 XML 文件中,从程序代码中彻底分离,即降低耦合度,又便于统一管理和优化,还可重用。
3、提供 XML 标签,支持编写动态 SQL 语句。
4、提供映射标签,支持对象与数据库的 ORM 字段关系映射。
数据持久化是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称。例如,文件的存储、数据的读取等都是数据持久化操作。数据模型可以是任何数据结构或对象模型,存储模型可以是关系模型、XML、二进制流等。
对象关系映射(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。
ORM是一种数据持久化技术。它在对象模型和关系型数据库之间建立起对应关系,并且提供了一种机制,通过 JavaBean 对象去操作数据库表中的数据。
在实际开发中,程序员使用面向对象的技术操作数据,而当存储数据时,使用的却是关系型数据库。ORM在对象模型和关系数据库的表之间建立了一座桥梁,有了它,程序员就不需要在使用 SQL 语句操作数据库中的表,使用 API 直接操作 JavaBean 对象就可以实现数据的存储、查询、更改和删除等操作。MyBatis 通过 XML 文件或注解进行配置和原始映射,在实体类和 SQL 语句之间建立映射关系,是一种半自动化的 ORM 实现。
基于 ORM, MyBatis 在对象模型和关系数据库的表之间建立了一座桥梁。通过 MyBatis,可以建立 SQL 关系映射,便捷地实现数据存储、查询、更改和删除等操作。
持久化类是指其实例状态需要被 MyBatis 持久化到数据库中的类。在应用的设计中,持久化类通常对应需求中的业务实体。MyBatis 一般采用 POJO(Plain Ordinary Java Object)编程模型来实现持久化类,与 POJO 类配合完成持久化工作是 MyBatis 最常见的工作模式。
POJO 从字面上来讲就是普通 Java 对象。POJO 类可以理解为符合 JavaBean 规范的实体类,它不需要继承和实现任何特殊的 Java 基类或者接口。JavaBean 对象的状态保存在属性中,访问属性必须通过对应的 getter 和 setter 方法。
点击“See the docs”查看MyBatis的文档(英文文档)。
点击“Download Latest”下载最新版本的MyBatis。
点击“Download Latest”。
New -> Project
选择“Maven Project”,点击“Next”。
将 “Create a simple project (skip archetype selection)” 前面的钩选中,点击 “Next”。
点击“Next”。
填写“Group Id”、“Artifact Id”、“Package”,点击“Finish”
maven工程目录结构如下:
打包方式:jar
<packaging>jarpackaging>
引入依赖
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.3version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.6version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>3.8.1version>
<scope>testscope>
dependency>
dependencies>
MyBatis 核心配置文件主要用于配置数据库连接和 MyBatis 运行时所需的各种特性,包含了设置和影响 MyBatis 行为的属性。
为了方便管理以后各框架集成所需的配置文件,需在项目工程下新建 Source Folder 类型的 resources 目录。为了在框架集成时更好地区分各个配置文件,我们一般将此文件命名为 “mybatis-config.xml”。该文件需要配置数据库连接信息和 MyBatis 的参数。
将来整合 Spring 之后,这个配置文件可以省略。
核心配置文件主要用于配置连接数据库的环境和 MyBatis 的全局配置信息。
核心配置文件存放的位置是 src/main/resources 目录下
MyBatis 核心配置文件配置了 MyBatis 的一些全局信息,包含数据库连接信息和 MyBatis 运行时所需的各种特性,以及设置和影响 MyBatis 行为的一些属性。
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.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test_jack"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
mappers>
configuration>
DOCTYPE configuration PUBLIC "-//MyBatis.org//DTD Config 3.0//EN" "http://MyBatis.org/dtd/MyBatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties"/>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="logImpl" value="LOG4J"/>
settings>
<typeAliases>
<package name="com.jack.mybatis.bean"/>
typeAliases>
<environments default="mysql_test">
<environment id="mysql_test">
<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>
<mappers>
<mapper resource="UserMapper.xml"/>
<package name="com.green.sea.mapper"/>
mappers>
configuration>
MyBatis核心配置文件中几个常用元素的作用如下:
configuration:配置文件的根元素节点。
properties:通过 resource 属性从外部指定 properties 属性文件(database.properties),该属性文件描述数据库连接的相关配置(数据库驱动driver、连接数据库的url、数据库用户名username、数据库密码password),其位置也是在 /resources 目录下。
settings:设置 MyBatis 运行中的一些行为,比如此处设置 MyBatis 的 log 日志实现为 LOG4J,即使用log4j 实现日志功能。
environments:表示配置 MyBatis 的多套运行环境,将 SQL 映射到多个不同的数据库上,该元素节点下可以配置多个 environment 子元素节点,但是必须指定其中一个为默认运行环境(通过 default属性指定)。
environment:配置 MyBatis 的一套运行环境,需指定运行环境 ID、事务管理、数据源配置等相关信息。
mappers:作用是 MyBatis 去哪里找到 SQL 映射文件(该文件内容是开发者定义的映射 SQL 语句),整个项目中可以有一个或多个 SQL 映射文件。
mapper:mappers 的子元素节点,具体指定 SQL 映射文件的路径,其中 resource 属性值表述了 SQL 映射文件的路径(类资源路径)。
核心配置文件中的标签必须按照固定的顺序:
properties
settings
typeAliases
typeHandlers
objectFactory
objectWrapperFactory
reflectorFactory
plugins
environments
databaseIdProvider
mappers
settings 元素的作用是设置一些非常重要的选项,用于设置和改变 MyBatis 运行中的行为。
settings 元素支持的属性:
设置项 | 描述 | 运行值 | 默认值 |
---|---|---|---|
cacheEnabled | 对在此配置文件下的所有 cache 进行全局性开/关设置 | true|false | true |
lazyLoadingEnabled | 全局性设置懒加载。如果设为 false,则所有相关联的设置都会被初始化加载。 | true|false | true |
autoMappingBehavior | MyBatis 对于 resultMap 自动映射的匹配级别。 | NONE|PARTIAL|FULL | PARTIAL |
typeAliases 元素的作用是配置类型别名,通过与 MyBatis 的 SQL 映射文件相关联,减少输入多余的完整类名,以简化操作。
<typeAliases>
<typeAlias alias="user" type="com.greensea.manage.pojo.User"/>
<typeAlias alias="provider" type="com.greensea.manage.pojo.Provider"/>
typeAliases>
或
<typeAliases>
<package name="com.greensea.manage.pojo"/>
typeAliases>
MyBatis 可以配置多套运行环境,如开发环境、测试环境、生产环境等,我们可以灵活选择不同的配置,从而将SQL映射到不同的数据库环境上。不同的运行环境可以通过environments元素来配置,但是不管增加几套运行环境,都必须要明确选择出当前唯一的一个运行环境。这是因为每个数据库都对应一个SqlSessionFactory实例,需要指明哪个运行环境将被创建,并把运行环境中设置的参数传递给SqlSessionFactory。
具体配置代码如下:
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
transactionManager>
<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>
1、默认的运行环境ID:通过default属性来指定当前的运行环境ID为development,对于环境ID的命名要确保唯一。
2、transactionManager事务管理器:设置其类型为JDBC(MyBatis有两种事务管理类型,即JDBC和MANAGED),直接使用JDBC的提交和回滚功能,依赖于从数据源获得连接来管理事务的生命周期。
3、dataSource元素:使用标准的JDBC数据源接口来配置JDBC连接对象的资源。MyBatis提供了三种数据源类型(UNPOOLED、POOLED、JNDI),这里使用POOLED数据源类型。该类型利用“池”的概念将JDBC连接对象组织起来,减少了创建新的连接实例时所必需的初始化和认证时间,是MyBatis实现的简单的数据库连接池类型,它使数据库连接可被复用,不必在每次请求时都去创建一个物理连接。对于高并发的Web应用,这是一种流行的处理方式,有利于快速响应请求。
mappers映射器用来定义SQL的映射语句,我们只需要告诉MyBatis去哪里找到这些SQL语句,即去哪里找相应的SQL映射文件,可以使用类资源路径或者URL等。
使用类资源路径获取资源
<mappers>
<mapper resource="mappers/UserMapper.xml" />
<mapper resource="mappers/EmployeeMapper.xml"/>
mappers>
使用URL获取资源
<mappers>
<mapper url="file:///E:/sqlmappers/UserMapper.xml"/>
<mapper url="file:///E:/sqlmappers/ProviderMapper.xml"/>
mappers>
在 MyBatis 中,不需要 POJO 类名与数据库表名一致,因为 MyBatis 是 POJO 与 SQL 语句之间的映射机制,一般情况下,保证 POJO 对象的属性与数据库表的字段名一致即可。
表名:t_user
字段名 | 字段说明 | 数据类型 | 说明 |
---|---|---|---|
id | 主键ID | bigint | 主键;自动递增;不允许为空 |
username | 用户名 | varchar(20) | |
password | 密码 | varchar(20) | |
age | 年龄 | tinyint | |
电子邮箱 | varchar(20) |
创建包:com.greensea.manage.entity
在该包下创建User.java
package com.greensea.manage.entity;
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String username;
private String password;
private Integer age;
private String email;
public User() {
}
public User(String username, String password, Integer age, String email) {
this.username = username;
this.password = password;
this.age = age;
this.email = email;
}
public User(Integer id, String username, String password, Integer age, String email) {
this.id = id;
this.username = username;
this.password = password;
this.age = age;
this.email = email;
}
public Integer getId() {
return id;
}
public void setId(Integer 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;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password="
+ password + ", age=" + age + ", email=" + email + "]";
}
}
MyBatis 中的 mapper 接口相当于以前的dao。但是区别在于 mapper 仅仅是接口,不需要提供实现类。
package com.greensea.manage.mapper;
public interface UserMapper {
/**
* 插入一条User数据
* @return 1,插入成功
*/
int insertUser();
}
SQL 映射文件的几个顶级元素配置:
1、用于区分不同的mapper,全局唯一。
2、绑定DAO接口,即面向接口编程。当namespace绑定某一接口之后,可以不用写该接口的实现类,MyBatis会通过接口的完整限定名查找到对应的mapper配置来执行SQL语句。因此namesp的命名必须跟接口同名。
MyBatis的SQL映射文件中mapper元素的namespace属性有如下要求:
1、namespace的命名必须跟某个DAO接口同名。
2、在不同的mapper文件中,子元素的id可以相同,MyBatis通过namespace和子元素的id联合区分。接口中的方法与映射文件中SQL语句id应一一对应。
SQL 映射文件一般都对应于相应的 POJO,所以一般都是以 POJO 的名称 +Mapper 的规则来命名。当然该 mapper 文件属于 DAO 层的操作,应该放置在 dao 包下(也可以放置在resources资源文件目录下),并根据业务功能进行分包放置。
ORM(Object Relational Mapping):对象关系映射。
Java概念 | 数据库概念 |
---|---|
类 | 表 |
属性 | 字段/列 |
对象 | 记录/行 |
1、表所对应的实体类的类名+Mapper.xml
例如:表t_user,映射的实体类为User,所对应的映射文件为UserMapper.xml,因此一个映射文件对应一个实体类,对应一张表的操作。
2、MyBatis映射文件用于编写SQL,访问以及操作表中的数据。
3、MyBatis映射文件存放的位置是src/main/resources/mappers目录下。
MyBatis中可以面向接口操作数据,要保证两个一致:
1、mapper接口的全类名和映射文件的命名空间(namespace)保持一致。
2、mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致。
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.green.sea.mapper.UserMapper">
<insert id="insertUser">
insert into t_user values (null, "宋江", "songjiang", 50, "[email protected]");
insert>
mapper>
各元素的含义如下:
mapper:映射文件的根元素节点,只有一个属性 namespace。
namespace:用于区分不同的 mapper,全局唯一。
MyBatis 的三个基本要素:
1、核心接口和类。
2、MyBatis 核心配置文件(mybatis-config.xml)。
3、SQL 映射文件(mapper.xml)
MyBatis 的核心接口和类
1、每个 MyBatis 的应用程序都以一个 SqlSessionFactory 对象的实例为核心。
2、首先获取 SqlSessionFactoryBuilder 对象,可以根据 XML 或 Configuration 类的实例构建该对象。
3、然后获取SqlSessionFactory 对象,该对象实例可以通过 SqlSessionFactoryBuilder 对象获得。
4、有了 SqlSessionFactory 对象之后,进而可以获取 SqlSession 实例,SqlSession 对象中完全包含以数据库为背景的所有执行 SQL 操作的方法。可以用该实例来直接执行已映射的 SQL 语句。
package com.company.project.module.first.test;
import java.io.IOException;
import java.io.InputStream;
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 com.company.project.module.first.mapper.UserMapper;
import com.company.project.module.first.util.MyBatisUtil;
public class TestUser {
public static void main(String[] args) {
InputStream inputStream = null;
SqlSessionFactory sqlSessionFactory = null;
try {
//读取MyBatis的核心配置文件
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//通过核心配置文件所对应的字节输入流创建工厂类SqlSessionFactory,生产SqlSession对象
sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
if(inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//创建SqlSession对象,此时通过SqlSession对象所操作的sql都必须手动提交或回滚事务
//SqlSession sqlSession = sqlSessionFactory.openSession();
//创建SqlSession对象,此时通过SqlSession对象所操作的sql都会自动提交
SqlSession sqlSession = sqlSessionFactory.openSession(true); //传入ture,则自动提交事务,默认为不提交。
//通过代理模式创建UserMapper接口的代理实现类对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用UserMapper接口中的方法,就可以根据UserMapper的全接口名匹配元素文件,通过调用的方法名匹配映射文件中的SQL。
int result = userMapper.insertUser();
//sqlSession.commit(); //提交事务
sqlSession.close();
System.out.println("返回结果:" + result);
}
}
SqlSessionFactoryBuilder 负责构建 SqlSessionFactory,并且提供了多个 build() 方法的重载。
SqlSessionFactory build(Reader reader)
SqlSessionFactory build(Reader reader, String environment)
SqlSessionFactory build(Reader reader, Properties properties)
SqlSessionFactory build(Reader reader, String environment, Properties properties)
SqlSessionFactory build(InputStream inputStream)
SqlSessionFactory build(InputStream inputStream, String environment)
SqlSessionFactory build(InputStream inputStream, Properties properties)
SqlSessionFactory build(InputStream inputStream, String environment, Properties properties)
SqlSessionFactory build(Configuration config)
配置信息以三种形式提供给 SqlSessionFactoryBuilder 的 build() 方法,分别是 InputStream(字节流)、Reader(字符流)、Configuration(类),由于字节流与字符流都属于读取配置文件的方式,所以从配置信息的来源去构建一个 SqlSessionFactory 有两种方式:读取 XML 配置文件构造方式和编程构造方式。
SqlSessionFactoryBuild 最大特点就是用过即丢。一旦创建了SqlSessionFactory 对象,这个类就不需要存在了,因此 SqlSessionFactoryBuilder 的最佳使用范围就是存在于方法体内,也就是局部变量。
SqlSessionFactory 就是创建 SqlSession 实例的工厂。所有的 MyBatis 应用都是以 SqlSessionFactory 实例为中心。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 对象来获得。有了 SqlSessionFactory 的实例,就可以通过 SqlSessionFactory 提供的openSession() 方法来获取 SqlSession 实例。
SqlSession openSession();
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
SqlSessionFactory 对象一旦创建,就会在这个应用运行过程中始终存在。没有理由去销毁或再创建它,并且在应用运行中也不建议多次创建 SqlSessionFactory。因此 SqlSessionFactory 的最佳作用域是 Application,即随着应用的生命周期一同存在。那么这种“存在于整个应用运行期间有且仅有一个实例”的模式就是所谓的单例模式(指在应用运行期间有且仅有一个实例)。
SqlSession 用于执行持久化操作的对象,类似于 JDBC 中的 Connection。它提供了面向数据库执行 SQL 命令所需的所有方法,可以通过 SqlSession 实例直接运行已映射的 SQL 语句。
SqlSession 对应着一次数据库会话,由于数据库会话不是永久的,因此 SqlSession 的生命周期也不是永久的。相反,在每次访问数据库时都需要创建它(注意:并不是说在 SqlSession 里只能执行一次 SQL,它是完全可以执行多次的,但是若关闭了 SqlSession,那么就需要重新创建它)。创建 SqlSession 的方式只有一个,那就是使用 SqlSessionFactory 对象的 openSession() 方法。
每个线程都有自己的 SqlSession 实例,SqlSession 实例不能被共享,也不是线程安全的。因此最佳的作用域范围是 request 作用域或者方法体作用域。
package com.company.project.module.first.util;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtil {
private static SqlSessionFactory sqlSessionFactory = null;
static {
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}finally {
if(inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static SqlSession createSqlSession() {
return sqlSessionFactory.openSession(true);
}
public static void closeSqlSession(SqlSession sqlSession) {
if(null != sqlSession) {
sqlSession.close();
}
}
}
package com.company.project.module.first.test;
import java.io.IOException;
import java.io.InputStream;
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 com.company.project.module.first.mapper.UserMapper;
import com.company.project.module.first.util.MyBatisUtil;
public class TestUser {
public static void main(String[] args) {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int result = userMapper.insertUser();
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println("result=" + result);
}
}
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
log4j的配置文件名为log4j.xml,存放的位置是src/main/resources目录下
DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name= "Encoding" value="UTF-8"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
layout>
appender>
<logger name="java.sql">
<level value="debug"/>
logger>
<logger name="org.apache.ibatis">
<level value="info"/>
logger>
<root>
<level value="debug"/>
<appender-ref ref="STDOUT" />
root>
log4j:configuration>
日志的级别:
FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)
从左到右打印的内容越来越详细。
UserMapper.java文件中添加:
/**
* 根据id修改一条User数据
* @return 1,修改成功
*/
int updateUserById();
UserMapper.xml文件中添加:
<update id="updateUserById">
update t_user set username="卢俊义" where id=1;
update>
测试方法:
@Test
public void testUpdateUserById() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int result = userMapper.updateUserById();
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println("结果:" + result);
}
UserMapper.java 文件中添加:
/**
* 根据id删除一条User数据
* @return 1,删除成功
*/
int deleteUserById();
UserMapper.xml 文件中添加:
<delete id="deleteUserById">
delete from t_user where id=1;
delete>
测试方法:
@Test
public void testDeleteUserById() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int result = userMapper.deleteUserById();
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println("结果:" + result);
}
UserMapper.java添加:
/**
* 根据id查询一条User数据
* @return 一条User数据
*/
User selectUserById();
/**
* 查询所有User信息
* @return 所有User
*/
List<User> selectUserAll();
UserMapper.xml添加:
<select id="selectUserById" resultType="com.greensea.manage.entity.User">
select * from t_user where id=2;
select>
<select id="selectUserAll" resultType="com.greensea.manage.entity.User">
select * from t_user;
select>
查询功能的标签必须设置resultType或resultMap
resultType:设置默认的映射关系。字段名和属性名相同时。
resultMap:设置自定义的映射关系。
select:表示查询语句,是 MyBatis 最常见的元素之一,常用属性如下:
id:该命名空间下唯一标识符。
resultType:表示 SQL 语句返回值类型,此处通过 SQL 语句返回的是 int 数据类型。
测试类:
@Test
public void testSelectUserById() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.selectUserById();
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(user);
}
@Test
public void testSelectUserAll() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectUserAll();
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(users);
}
- 查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射关系。
resultType:自动映射,用于属性名和表中字段名一致的情况。
resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况。- 当查询的数据为多条时,不能使用实体类作为返回值,只能使用集合,否则会抛出异常:TooManyResultsException;
若查询的数据只有一条,可以使用实体类或集合作为返回值。
MyBatis 获取参数值的两种方式:${} 和 #{}
${} 的本质就是字符串拼接,#{} 的本质是占位符赋值。
${} 使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是 #{} 使用占位符赋值的方式拼接 sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号。
若mapper接口中的方法参数为单个的字面量类型。此时可以使用${}和#{}以任意的名称获取参数的值,注意${}需要手动加单引号。
UserMapper.java
/**
* 根据id查询一条User数据
* @return 一条User数据
*/
User selectUserById1(Integer id);
UserMapper.xml
<select id="selectUserById1" resultType="com.greensea.manage.entity.User">
select * from t_user where id=#{id};
select>
测试:
@Test
public void testSelectUserById1() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.selectUserById1(2);
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(user);
}
若 mapper 接口中的方法参数为多个时,MyBatis 会自动将这些参数放在一个 map 集合中,以 arg0, arg1…为键,以参数为值;以 param1, param2…为键,以参数为值;因此只需要通过 ${} 和 #{} 访问 map 集合的键就可以获取相对应的值,注意${}需要手动加单引号。
UserMapper.java
/**
* 根据用户名和密码查询用户
* @param User对象
* @return 查询的用户集合
*/
List<User> selectUserByUsernameAndPassword(String username, String password);
UserMapper.xml
<select id="selectUserByUsernameAndPassword" resultType="com.greensea.manage.entity.User">
select * from t_user where username=#{param1} and password=#{param2};
select>
测试
@Test
public void testSelectUserByUsernameAndPassword() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectUserByUsernameAndPassword("宋江", "songjiang");
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(users);
}
若mapper接口中的方法需要的参数为多个时,可以手动创建map集合,将这些数据放在map中,只需要通过${}和#{}访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号。
UserMapper.java
/**
* 根据用户名和密码查询用户
* @param map集合
* @return 查询的用户集合
*/
List<User> selectUserByUsernameAndPassword1(Map<String, Object> map);
UserMapper.xml
<select id="selectUserByUsernameAndPassword1" resultType="com.greensea.manage.entity.User">
select * from t_user where username=#{username} and password=#{password};
select>
测试
@Test
public void testSelectUserByUsernameAndPassword1() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("username", "宋江");
map.put("password", "songjiang");
List<User> users = userMapper.selectUserByUsernameAndPassword1(map);
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(users);
}
若mapper接口中的方法参数为实体类对象时,可以使用${}和#{},通过访问实体类对象中的属性名获取属性值,注意${}需要手动加单引号
UserMapper.java
/**
* 插入一条用户数据
* @param User用户
* @return 返回1,插入成功
*/
int insertUserParamUser(User user);
UserMapper.xml
<insert id="insertUserParamUser">
insert into t_user values (null, #{username}, #{password}, #{age}, #{email});
insert>
insert元素包括如下属性:
1、id:与select元素的id一样,是命名空间中唯一的标识符,可以被用来引用该条语句。
2、parameterType:与select元素的parameterType一样,是传入参数的类型的完全限定名或别名。
对于增删改(insert、delete、update)这类数据库更新操作,需要注意两点:
1、该类型的操作本身默认返回执行SQL语句影响的行数,所有DAO层的接口方法的返回值一般设置为int类型。最好不要返回boolean类型。
2、insert、delete、update元素中均没有resultType属性,只有查询操作需要对返回结果的类型(resultType/resultMap)进行相应的指定。
测试
@Test
public void testInsertUserParamUser() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
/*User user = new User();
user.setUsername("宋江");
user.setPssword("songjiang");
user.setAge(56);
user.setEmail("[email protected]");*/
User user = new User("宋江", "songjiang", 56, "[email protected]");
int result = userMapper.insertUserParamUser(user);
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(result);
}
UserMapper.java
/**
* 根据用户名和密码查询用户信息
* @param 用户名
* @param 密码
* @return 用户的集合
*/
List<User> selectUserByUsernameAndPasswordParamUser(User user);
UserMapper.xml
<select id="selectUserByUsernameAndPasswordParamUser" resultType="com.greensea.manage.entity.User">
select * from t_user where username=#{username} and password=#{password};
select>
测试
@Test
public void selectUserByUsernameAndPasswordParamUser() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setUsername("宋江");
user.setPassword("songjiang");
List<User> users = userMapper.selectUserByUsernameAndPasswordParamUser(user);
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(users);
}
使用@Param标识参数,可以通过@Param注解标识mapper接口中的方法参数。此时,会将这些参数放在 map 集合中,以 @Param 注解的value 属性值为键,以参数为值;以 param1, param2…为键,以参数为值;只需要通过 ${} 和 #{} 访问 map 集合的键就可以获取相对应的值,注意 ${} 需要手动加单引号。
UserMapper.java
/**
* 根据用户名和密码查询用户
* @param User对象
* @return 查询的用户集合
*/
List<User> selectUserByUsernameAndPasswordParamUser1(@Param("username") String username, @Param("password") String password);
UserMapper.xml
<select id="selectUserByUsernameAndPasswordParamUser1" resultType="com.greensea.manage.entity.User">
select * from t_user where username=#{username} and password=#{password};
select>
测试
@Test
public void selectUserByUsernameAndPasswordParamUser1() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectUserByUsernameAndPasswordParamUser1("宋江", "songjiang");
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(users);
}
MyBatis 的各种查询功能:
1、若查询出的数据(对象)只有一条
(1)可以通过实体类对象接收。(User)
(2)可以通过list集合接收。(List、List
2、若查询出的数据有多条
(1)可以通过实体类类型的 list 集合接收。(List)
(2)可以通过 map 类型的 list 集合接收。(List
注意:一定不能通过实体类对象接收,此时会抛异常 TooManyResultsException。
只适用于返回一条数据
/**
* 根据用户id查询用户信息
* @param 用户id
* @return 一条用户信息
*/
User selectUserById(@Param("id") Integer id);
<select id="selectUserById" resultType="User">
select * from t_user where id=#{id};
select>
@Test
public void testSelectUserById() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.selectUserById(2);
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(user);
}
适用于返回一条或一条以上数据
/**
* 查询所有User信息
* @return 所有User;List集合,里面的元素是实体类对象
*/
List<User> selectUserAll();
<select id="selectUserAll" resultType="User">
select * from t_user;
select>
@Test
public void testSelectUserAll() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectUserAll();
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(users);
}
在 MyBatis 中,对于 Java 中常用的数据类型都设置了类型别名。
例如:
java.lang.Integer -> int | integer
int -> _int | _integer
String -> string
List -> list
Map -> map
/**
* 查询共有多少用户
* @return 用户总数
*/
int selectUserCount();
<select id="selectUserCount" resultType="Integer">
select count(*) from t_user;
select>
@Test
public void tsetSelectUserCount() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int count = userMapper.selectUserCount();
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(count);
}
对于resultType值,即返回结果,MyBatis 提供的类型别名如下:
Alias | Mapped Type |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
只适用于返回一条数据。
/**
* 根据用户id查询用户
* @param id
* @return 一条用户数据,将该用户数据以属性为key,属性值为value存放在map集合中
*/
Map<String, Object> selectUserByIdMap(@Param("id") Integer id);
<select id="selectUserByIdMap" resultType="map">
select * from t_user where id=#{id};
select>
@Test
public void selectUserByIdMap(){
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = userMapper.selectUserByIdMap(1);
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(map);
}
以上代码输出结果为 map 类型,key为属性名称,值为属性值。
返回结果形式:{password=123456, sex=男, id=1, age=23, [email protected], username=admin}
/**
* 查询所有用户信息,放在List集合中,集合中的元素为map集合,该集合中存放的key为属性名称,value为属性值
* 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,此时可以将这些map放在一个list集合中获取
* @return 用户数据,将该用户数据以属性为key,属性值为value存放在map集合中
*/
List<Map<String, Object>> selectAllUserListInMap();
<select id="selectAllUserListInMap" resultType="map">
select * from t_user;
select>
@Test
public void selectAllUserListInMap(){
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<Map<String, Object>> listInMap = userMapper.selectAllUserListInMap();
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(listInMap);
for (int i = 0; i < listInMap.size(); i++) {
System.out.println(listInMap.get(i));
}
}
/**
* 查询所有用户信息为map集合
* 将表中的数据以map集合的方式查询,一条数据对应一个map;
* 若有多条数据,就会产生多个map集合,并且最终以一个map的方式返回数据,此时需要通过@MapKey注解设置map集合的键,值是每条数据所对应的map集合
* @return map集合
*/
@MapKey(value = "id")
Map<String, Object> selectAllUserMap();
<select id="selectAllUserMap" resultType="map">
select * from t_user;
select>
@Test
public void selectAllUserMap(){
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = userMapper.selectAllUserMap();
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(map);
}
结果:
{
1={password=123456, sex=男, id=1, age=23, username=admin},
2={password=123456, sex=男, id=2, age=23, username=张三},
3={password=123456, sex=男, id=3, age=23, username=张三}
}
@MapKey("id")
Map<String, Object> selectUserByUsernameAnnotation(@Param("username") String username);
<select id="selectUserByUsernameAnnotation" resultType="map">
select * from t_user where username=#{username};
select>
@Test
public void selectUserByUsernameAnnotation() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = userMapper.selectUserByUsernameAnnotation("潘金莲");
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(map);
}
UserMapper.java
/**
* 模糊查询
* @param 模糊查询的条件
* @return 用户数据集合
*/
List<User> selectUserLike(@Param("username") String username);
UserMapper.xml
<select id="selectUserLike" resultType="User" parameterType="String">
select * from t_user where username like concat('%', #{username}, '%');
select>
test
@Test
public void testSelectUserLike() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectUserLike("卢");
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(users);
}
parameterType表示查询语句传入参数的类型的完全限定名或别名。它支持基础数据类型和复杂数据类型。
/**
* 批量删除
* @param id
* @return 删除个数
*/
int deleteBatch(@Param("ids") String ids);
<delete id="deleteBatch">
delete from t_user where id in (${ids});
delete>
@Test
public void deleteBatch() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int number = userMapper.deleteBatch("1, 2, 3");
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(number);
}
/**
* 查询所有用户信息
* @param 表名
* @return 表中所有数据
*/
List<User> selectAllUserTableName(@Param("tableName") String tableName);
<select id="selectAllUserTableName" resultType="User">
select * from ${tableName};
select>
@Test
public void selectAllUserTableName(){
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectAllUserTableName("t_user");
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(users);
for (User user : users) {
System.out.println(user);
}
}
useGeneratedKeys:设置使用自增的主键。
keyProperty:因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参数 user 对象的某个属性中
int insertUserId(User user);
<insert id="insertUserId" useGeneratedKeys="true" keyProperty="id">
insert into t_user values (null, #{username}, #{password}, #{age}, #{email});
insert>
@Test
public void insertUser(){
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User(null, "宋江", "123", 55, "[email protected]");
int number = userMapper.insertUserId(user);
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(number);
System.out.println(user);
}
若字段名和实体类中的属性名不一致,则可以通过 resultMap 设置自定义映射。
若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性名符合Java的规则(使用驼峰)。此时也可通过以下两种方式处理字段名和实体类中的属性的映射关系
1、可以通过为字段起别名的方式,保证和实体类中的属性名保持一致
2、可以在MyBatis的核心配置文件中设置一个全局配置信息 mapUnderscoreToCamelCase ,可以在查询表中数据时,自动将_类型的字段名转换为驼峰
例如:字段名user_name,设置了 mapUnderscoreToCamelCase ,此时字段名就会转换为 userName。
resultMap:设置自定义映射
属性:
id:表示自定义映射的唯一标识
type:查询的数据要映射的实体类的类型
子标签:
id:设置主键的映射关系
result:设置普通字段的映射关系
association:设置多对一的映射关系
collection:设置一对多的映射关系
属性:
property:设置映射关系中实体类中的属性名
column:设置映射关系中表中的字段名
resultMap元素包括如下属性值和子节点:
- id属性:唯一标识,此id值用于对select元素resultMap属性的引用
- type属性:表示该resultMap的映射结果类型。
- result子节点:用于标识一些简单属性,其中column属性表示从数据库中查询的字段名,property则表示查询出来的字段对应的值赋给实体对象的哪个属性。
1、resultType
resultType表示返回类型,包括基础数据类型和复杂数据类型。
2、resultMap
resultMap是对外部resultMap定义的引用,对应外部resultMap的id ,表示返回结果映射到哪一个resultMap上。它的应用场景一般是:数据库字段信息与对象属性不一致或者需要做复杂的联合查询,以便自由控制映射结果。
3、resultType和resultMap的关联
在MyBatis进行查询映射的时候,查询出来的每个字段值都放在一个对应的Map里面,其中键是字段名,值则是其对应的值。当select元素提供的返回类型属性是resultType的时候,MyBatis会将Map里面的键值对取出赋给resultType所指定的对象对应的属性(即调用对应的对象里的属性的setter方法进行填充)。正因为如此,当使用resultType的时候,直接在后台就能接收到其相应的对象属性值。由此可看出,其实MyBatis的每个查询映射的返回类型都是resultMap,只是当我们提供的返回类型属性是resultType的时候,MyBatis会自动把对应的值赋给resultType所指定对象的属性;而当我们提供的返回类型属性是resultMap的时候,因为Map不能很好地表示领域模型,就需要通过进一步的定义把它转化为对应的实体对象。
在MyBatis的select元素中,resultType和resultMap本质上是一样的,都是Map数据结构。但需要明确一点:resultType属性和resultMap属性绝对不能同时存在,只能二者选其一使用。
在MyBatis中,使用resultMap能够进行自动映射匹配的前提是字段名和属性名必须一致,在默认映射级别(PARTIAL)情况下,若字段名和属性名一致,即使没有做属性名的匹配,也可以在后台获取到未匹配过的属性值;若字段名和属性名不一致,且在resultMap里没有做映射,那么就无法在后台获取并输出。
<resultMap id="userMap" type="User">
<id property="id" column="id">id>
<result property="userName" column="user_name">result>
<result property="password" column="password">result>
<result property="age" column="age">result>
<result property="sex" column="sex">result>
resultMap>
<select id="testMohu" resultMap="userMap">
select id,user_name,password,age,sex from t_user where user_name like concat('%',#{mohu},'%')
select>
表名:t_employee
字段名 | 字段类型 | 长度 | 说明 |
---|---|---|---|
eid | bigint | 20 | 主键自增 |
emp_name | varchar | 255 | |
gender | tinyint | 4 | |
age | int | 11 | |
varchar | 255 | ||
did | bigint | 20 |
字段名 | 字段类型 | 长度 | 备注 |
---|---|---|---|
did | bigint | 20 | 主键自增 |
dept_name | varchar | 255 |
select * from t_employee, t_department where t_employee.did=t_department.did;
select * from t_employee
left join t_department
on t_employee.did=t_department.did;
select * from t_employee e
left join t_department d
on e.did=d.did;
select * from t_employee as e
left join t_department as d
on e.did=d.did;
select e.*, d.* from t_employee as e
left join t_department as d
on e.did=d.did;
select d.*, e.* from t_employee as e
left join t_department as d
on e.did=d.did;
select * from t_employee as e
left join t_department as d
on e.did=d.did
where e.did='2';
Employee.java
package com.greensea.manage.entity;
import java.io.Serializable;
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Integer eid;
private String empName;
private Integer gender;
private Integer age;
private String email;
private Integer did;
private Department department;
public Employee() {
}
public Employee(String empName, Integer gender, Integer age, String email, Integer did, Department department) {
this.empName = empName;
this.gender = gender;
this.age = age;
this.email = email;
this.did = did;
this.department = department;
}
public Employee(Integer eid, String empName, Integer gender, Integer age, String email, Integer did, Department department) {
this.eid = eid;
this.empName = empName;
this.gender = gender;
this.age = age;
this.email = email;
this.did = did;
this.department = department;
}
public Integer getEid() {
return eid;
}
public void setEid(Integer eid) {
this.eid = eid;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getDid() {
return did;
}
public void setDid(Integer did) {
this.did = did;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
@Override
public String toString() {
return "Employee [eid=" + eid + ", empName=" + empName + ", gender="
+ gender + ", age=" + age + ", email=" + email + ", did=" + did
+ ", department=" + department + "]";
}
}
department.java
package com.greensea.manage.entity;
import java.io.Serializable;
import java.util.List;
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
private Integer did;
private String deptName;
private List<Employee> employees;
public Department() {
}
public Department(String deptName, List<Employee> employees) {
this.deptName = deptName;
this.employees = employees;
}
public Department(Integer did, String deptName, List<Employee> employees) {
this.did = did;
this.deptName = deptName;
this.employees = employees;
}
public Integer getDid() {
return did;
}
public void setDid(Integer did) {
this.did = did;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
@Override
public String toString() {
return "Department [did=" + did + ", deptName=" + deptName + ", employees=" + employees + "]";
}
}
EmployeeMapper.java
/**
* 查询所有雇员信息
* @return 所有员工信息
*/
List<Employee> selectEmployeeAll();
EmployeeMapper.xml
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.greensea.manage.mapper.EmployeeMapper">
<resultMap type="Employee" id="employeeMap">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="gender" column="gender"/>
<result property="age" column="age"/>
<result property="email" column="email"/>
<result property="did" column="did"/>
resultMap>
<select id="selectEmployeeAll" resultMap="employeeMap">
select * from t_employee;
select>
mapper>
test
@Test
public void selectEmployeeAll() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
List<Employee> employees = employeeMapper.selectEmployeeAll();
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(employees);
for (Employee employee : employees) {
System.out.println(employee);
}
}
resultMap:设置自定义映射
属性:
id:表示自定义映射的唯一标识
type:查询的数据要映射的实体类的类型
子标签:
id:设置主键的映射关系
result:设置普通字段的映射关系
association:设置多对一的映射关系
collection:设置一对多的映射关系
属性:
property:设置映射关系中实体类中的属性名
column:设置映射关系中表中的字段名
EmployeeMapper.java
/**
* 根据员工id查询员工信息以及所在部门的信息。
* @param eid;员工id
* @return 查询到的员工
*/
Employee selectEmployeeAndDepartmentById(@Param("eid") Integer eid);
EmployeeMapper.xml
<resultMap id="employeeAndDepartmentMapOne" type="Employee">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="gender" column="gender"/>
<result property="age" column="age"/>
<result property="email" column="email"/>
<result property="did" column="did"/>
<result property="department.did" column="did"/>
<result property="department.deptName" column="dept_name"/>
resultMap>
<select id="selectEmployeeAndDepartmentById" resultMap="employeeAndDepartmentMapOne">
select * from t_employee left join t_department on t_employee.did=t_department.did where t_employee.eid=#{eid};
select>
test
@Test
public void selectEmployAndDepartmentById() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee = employeeMapper.selectEmployeeAndDepartmentById(1);
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(employee);
}
<resultMap id="employeeAndDepartmentMapTwo" type="Employee">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="gender" column="gender"/>
<result property="age" column="age"/>
<result property="email" column="email"/>
<result property="did" column="did"/>
<association property="department" javaType="Department">
<id property="did" column="did"/>
<result property="deptName" column="dept_name"/>
association>
resultMap>
<select id="selectEmployeeAndDepartmentById" resultMap="employeeAndDepartmentMapTwo">
select * from t_employee left join t_department on t_employee.did=t_department.did where t_employee.eid=#{eid};
select>
步骤一:根据员工eid查询员工信息
/**
* 处理多对一映射关系;分步查询;步骤一;根据员工eid查询一条员工信息
* @param 员工eid
* @return 员工信息
*/
Employee selectEmployeeByIdStepOne(@Param("id") Integer id);
<resultMap type="Employee" id="employeeResultMapStepOne">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="gender" column="gender"/>
<result property="age" column="age"/>
<result property="email" column="email"/>
<result property="did" column="did"/>
<association property="department" select="com.greensea.manage.mapper.DepartmentMapper.selectDepartmentByIdStepTwo" column="did"/>
resultMap>
<select id="selectEmployeeByIdStepOne" resultMap="employeeResultMapStepOne">
select * from t_employee where eid=#{id};
select>
步骤二:根据部门did查询部门信息
/**
* 处理多对一映射关系;分步查询;步骤二;根据部门did查询一条部门信息
* @param 部门did
* @return 部门信息
*/
Department selectDepartmentByIdStepTwo(@Param("id") Integer id);
<resultMap type="Department" id="departmentResultMapStepTwo">
<id property="did" column="did"/>
<result property="deptName" column="dept_name"/>
resultMap>
<select id="selectDepartmentByIdStepTwo" resultMap="departmentResultMapStepTwo">
select * from t_department where did=#{id};
select>
test
@Test
public void testSelectDepartmentByIdSteptwo() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
DepartmentMapper departmentMapper = sqlSession.getMapper(DepartmentMapper.class);
Department department = departmentMapper.selectDepartmentByIdStepTwo(1);
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(department);
}
@Test
public void testSelectEmployeeByIdStepOne() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee = employeeMapper.selectEmployeeByIdStepOne(1);
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(employee);
}
DepartmentMapper.java
/**
* 根据部门did查询一条部门信息;一对多
* @param 部门id
* @return 部门信息
*/
Department selectDepartmentByidEmployee(@Param("id") Integer id);
DepartmentMapper.xml
<resultMap type="Department" id="departmentEmployeeResultMap">
<id property="did" column="did"/>
<result property="deptName" column="dept_name"/>
<collection property="employees" ofType="Employee">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="gender" column="gender"/>
<result property="age" column="age"/>
<result property="email" column="email"/>
<result property="did" column="did"/>
collection>
resultMap>
<select id="selectDepartmentByidEmployee" resultMap="departmentEmployeeResultMap">
select * from t_department left join t_employee on t_department.did=t_employee.did where t_department.did=#{id};
select>
test
@Test
public void selectDepartmentByidEmployee() {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtil.createSqlSession();
DepartmentMapper departmentMapper = sqlSession.getMapper(DepartmentMapper.class);
Department department = departmentMapper.selectDepartmentByidEmployee(1);
System.out.println(department);
} catch (Exception e) {
e.printStackTrace();
//sqlSession.rollback();
}finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
}
步骤一:
DepartmentMapper.java
/**
* 处理一对多映射关系;分步查询;步骤一;根据部门编号查询出一条部门信息
* @param 部门编号
* @return 一条部门信息
*/
Department selectDepartmentByIdEmployeeStepOne(@Param("id") Integer id);
DepartmentMapper.xml
<resultMap type="Department" id="selectDepartmentByIdEmployeeStepOneResultMap">
<id property="did" column="did"/>
<result property="deptName" column="dept_name"/>
<collection property="employees" column="did" fetchType="eager" select="com.greensea.manage.mapper.EmployeeMapper.selectDepartmentByIdEmployeeStepTwo"/>
resultMap>
<select id="selectDepartmentByIdEmployeeStepOne" resultMap="selectDepartmentByIdEmployeeStepOneResultMap">
select * from t_department where did = #{id}
select>
步骤二:
EmployeeMapper.java
/**
* 处理一对多映射关系;分步查询;步骤二;根据员工部门编号查询出一条员工信息
* @param 员工部门的编号
* @return 一条员工信息
*/
Employee selectDepartmentByIdEmployeeStepTwo(@Param("id") Integer id);
EmployeeMapper.xml
<resultMap type="Employee" id="selectDepartmentByIdEmployeeStepTwoResultMap">
<id property="eid" column="eid"/>
<result property="empName" column="emp_name"/>
<result property="gender" column="gender"/>
<result property="age" column="age"/>
<result property="email" column="email"/>
resultMap>
<select id="selectDepartmentByIdEmployeeStepTwo" resultMap="selectDepartmentByIdEmployeeStepTwoResultMap">
select * from t_employee where did=#{id};
select>
test
@Test
public void TestSelectDepartmentByIdEmployeeStepTwo() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee = employeeMapper.selectDepartmentByIdEmployeeStepTwo(1);
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(employee);
}
@Test
public void testSelectDepartmentByIdEmployeeStepOne() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
DepartmentMapper departmentMapper = sqlSession.getMapper(DepartmentMapper.class);
Department department = departmentMapper.selectDepartmentByIdEmployeeStepOne(1);
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println(department);
}
分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载,此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType=“lazy(延迟加载)|eager(立即加载)”。
/**
* 多条件查询
* @param 实体类对象
* @return 对象集合
*/
List<Employee> selectEmployeeByCondition(Employee employee);
<select id="selectEmployeeByCondition" resultMap="employeeMap">
select * from t_employee where 1=1
<if test="empName != '' and empName != null">
and emp_name=#{empName}
if>
<if test="age != '' and age != null">
and age=#{age}
if>
<if test="sex != '' and sex != null">
and sex=#{sex}
if>
select>
@Test
public void selectEmployeeByCondition() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
List<Employee> employees = employeeMapper.selectEmployeeByCondition(new Employee(null, "宋江", null, "男", "[email protected]", 1));
for (Employee employee : employees) {
System.out.println(employee);
}
}
/**
* 多条件查询;where的使用
* @param 实体类对象
* @return 对象集合
*/
List<Employee> selectEmployeeByConditionWhere(Employee employee);
<select id="selectEmployeeByConditionWhere" resultMap="employeeMap">
select * from t_employee
<where>
<if test="empName != '' and empName != null">
emp_name=#{empName}
if>
<if test="age != '' and age != null">
and age=#{age}
if>
<if test="sex != '' and sex != null">
and sex=#{sex}
if>
where>
select>
@Test
public void selectEmployeeByConditionWhere() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
List<Employee> employees = employeeMapper.selectEmployeeByConditionWhere(new Employee(null, "宋江", null, "男", "[email protected]", 1));
for (Employee employee : employees) {
System.out.println(employee);
}
}
where 和 if 一般结合使用:
若 where 标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字
若 where 标签中的if条件满足,则 where 标签会自动添加 where 关键字,并将条件最前方多余的 and 去掉
where 标签不能去掉条件最后多余的 and 。
EmployeeMapper.java
/**
* 批量删除
* @param 数组
* @return 删除影响行数
*/
int deleteEmplyoeeBatchArray(@Param("ids") Integer[] ids);
EmployeeMapper.xml
<delete id="deleteEmplyoeeBatchArray">
delete from t_employee where eid in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
foreach>
delete>
日志输出信息:
DEBUG 04-08 16:56:02,476 ==> Preparing: delete from t_employee where eid in ( ? , ? , ? ) (BaseJdbcLogger.java:137)
DEBUG 04-08 16:56:02,508 > Parameters: 5(Integer), 6(Integer), 7(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-08 16:56:02,511 < Updates: 3 (BaseJdbcLogger.java:137)
结果:3
<delete id="deleteEmplyoeeBatchArray">
delete from t_employee where
<foreach collection="ids" item="id" separator="or" open="where">
eid=#{id}
foreach>
delete>
日志输出信息:
DEBUG 04-08 17:12:47,834 ==> Preparing: delete from t_employee where eid=? or eid=? or eid=? (BaseJdbcLogger.java:137)
DEBUG 04-08 17:12:47,856 > Parameters: 8(Integer), 9(Integer), 10(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-08 17:12:47,870 < Updates: 3 (BaseJdbcLogger.java:137)
结果:3
test
@Test
public void testDeleteEmplyoeeBatchArray() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
Integer[] array = new Integer[] {8, 9, 10};
int deleteResultCount = employeeMapper.deleteEmplyoeeBatchArray(array);
System.out.println("结果:" + deleteResultCount);
}
collection:设置要循环的数组或集合
item:表示集合或数组中的每一个数据
separator:设置循环体之间的分隔符
open:设置foreach标签中的内容的开始符
close:设置foreach标签中的内容的结束符
EmployeeMapper.java
/**
* 批量添加
* @param employees集合
* @return 插入成功的条数
*/
int insertEmployeeBatchList(@Param("employees") List<Employee> employees);
EmployeeMapper.xml
<insert id="insertEmployeeBatchList">
insert into t_employee values
<foreach collection="employees" item="employee" separator=",">
(null, #{employee.empName}, #{employee.gender}, #{employee.age}, #{employee.email}, #{employee.did})
foreach>
insert>
test
@Test
public void testInsertEmployeeBatchList() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee = new Employee("宋江", 1, 55, "[email protected]", 2, null);
Employee employee1 = new Employee("卢俊义", 1, 56, "[email protected]", 2, null);
Employee employee2 = new Employee("吴用", 1, 57, "[email protected]", 2, null);
List<Employee> employees = Arrays.asList(employee, employee1, employee2);
int insertResultCount = employeeMapper.insertEmployeeBatchList(employees);
MyBatisUtil.closeSqlSession(sqlSession);
System.out.println("结果:" + insertResultCount);
}
日志输出结果:
DEBUG 04-08 18:19:24,298 ==> Preparing: insert into t_employee values (null, ?, ?, ?, ?, ?) , (null, ?, ?, ?, ?, ?) , (null, ?, ?, ?, ?, ?) (BaseJdbcLogger.java:137)
DEBUG 04-08 18:19:24,343 ==> Parameters: 宋江(String), 1(Integer), 55(Integer), [email protected](String), 2(Integer), 卢俊义(String), 1(Integer), 56(Integer), [email protected](String), 2(Integer), 吴用(String), 1(Integer), 57(Integer), [email protected](String), 2(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-08 18:19:24,347 <== Updates: 3 (BaseJdbcLogger.java:137)
结果:3
SQL片段,可以记录一段公共SQL片段,在使用的地方通过include标签进行引入。
<sql id="empColumns">
eid, ename, age, sex, did
sql>
select <include refid="empColumns">include> from t_emp;
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。
使一级缓存失效的四种情况:
1、不同的SqlSession对应不同的一级缓存。
2、同一个SqlSession但是查询条件不同。
3、同一个SqlSession两次查询期间执行了任何一次增删改操作。
4、同一个SqlSession两次查询期间手动清空了缓存。
下列案例使用了一级缓存,只执行了一次SQL
@Test
public void testSelectUserAll() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.findAllUser();
List<User> users1 = userMapper.findAllUser();
MyBatisUtil.closeSqlSession(sqlSession);
users.forEach(System.out::println);
System.out.println("****************");
users1.forEach(System.out::println);
}
DEBUG 04-09 08:49:34,212 ==> Preparing: select * from t_user; (BaseJdbcLogger.java:137)
DEBUG 04-09 08:49:34,242 ==> Parameters: (BaseJdbcLogger.java:137)
DEBUG 04-09 08:49:34,265 <== Total: 11 (BaseJdbcLogger.java:137)
不同的SqlSession对应不同的一级缓存。
@Test
public void testSelectUserAll() {
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.findAllUser();
SqlSession sqlSession1 = MyBatisUtil.createSqlSession();
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
List<User> users1 = userMapper1.findAllUser();
MyBatisUtil.closeSqlSession(sqlSession);
MyBatisUtil.closeSqlSession(sqlSession1);
users.forEach(System.out::println);
System.out.println("****************");
users1.forEach(System.out::println);
}
DEBUG 04-09 08:52:22,531 ==> Preparing: select * from t_user; (BaseJdbcLogger.java:137)
DEBUG 04-09 08:52:22,588 ==> Parameters: (BaseJdbcLogger.java:137)
DEBUG 04-09 08:52:22,604 <== Total: 11 (BaseJdbcLogger.java:137)
DEBUG 04-09 08:52:22,623 ==> Preparing: select * from t_user; (BaseJdbcLogger.java:137)
DEBUG 04-09 08:52:22,624 ==> Parameters: (BaseJdbcLogger.java:137)
DEBUG 04-09 08:52:22,628 <== Total: 11 (BaseJdbcLogger.java:137)
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取.
二级缓存开启的条件:
1、在核心配置文件中,设置全局配置属性cacheEnabled=“true”,默认为true,不需要设置
2、在映射文件中设置标签
3、二级缓存必须在SqlSession关闭或提交之后有效
4、查询的数据所转换的实体类类型必须实现序列化的接口
使二级缓存失效的情况:两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效。
在mapper配置文件中添加的cache标签可以设置一些属性:
eviction属性:缓存回收策略
LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU。
flushInterval属性:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
size属性:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出
readOnly属性:只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存。
如果一级缓存也没有命中,则查询数据库。
SqlSession关闭之后,一级缓存中的数据会写入二级缓存。
<dependency>
<groupId>org.mybatis.cachesgroupId>
<artifactId>mybatis-ehcacheartifactId>
<version>1.2.1version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
各jar包功能
jar包名称 | 作用 |
---|---|
mybatis-ehcache | Mybatis和EHCache的整合包 |
ehcache | EHCache核心包 |
slf4j-api | SLF4J日志门面包 |
logback-classic | 支持SLF4J门面接口的一个具体实现 |
DOCTYPE xml>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="D:\data\mybatis\ehcache"/>
<defaultCache>
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
defaultCache>
ehcache>
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
存在SLF4J时,作为简易日志的log4j将失效,此时需要SLF4J的具体实现logback来打印日志。
创建logback的配置文件logback.xml。
DOCTYPE xml>
<configuration debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n
pattern>
encoder>
appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
root>
<logger name="com.jack.crowd.mapper" level="DEBUG" />
configuration>
EHCache的配置文件说明
属性名 | 是否必须 | 作用 |
---|---|---|
maxElementsInMemory | 是 | 在内存中缓存的element的最大数目 |
maxElementsOnDisk | 是 | 在磁盘上缓存的element的最大数目,若是0表示无穷大 |
eternal | 是 | 设定缓存的elements是否永远不过期。 如果为true,则缓存的数据始终有效, 如果为false那么还要根据timeToIdleSeconds、timeToLiveSeconds判断 |
overflowToDisk | 是 | 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上 |
timeToIdleSeconds | 否 | 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时, 这些数据便会删除,默认值是0,也就是可闲置时间无穷大 |
timeToLiveSeconds | 否 | 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大 |
diskSpoolBufferSizeMB | 否 | DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区 |
diskPersistent | 否 | 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。 |
diskExpiryThreadIntervalSeconds | 否 | 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s, 相应的线程会进行一次EhCache中数据的清理工作 |
memoryStoreEvictionPolicy | 否 | 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。 默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出) |
正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
1、Java实体类
2、Mapper接口
3、Mapper映射文件
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.seagreengroupId>
<artifactId>maven_mybatis_1artifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>jarpackaging>
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.3version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.9version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.9version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.mybatis.cachesgroupId>
<artifactId>mybatis-ehcacheartifactId>
<version>1.2.1version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generatorgroupId>
<artifactId>mybatis-generator-maven-pluginartifactId>
<version>1.3.0version>
<dependencies>
<dependency>
<groupId>org.mybatis.generatorgroupId>
<artifactId>mybatis-generator-coreartifactId>
<version>1.3.2version>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>c3p0artifactId>
<version>0.9.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.8version>
dependency>
dependencies>
plugin>
plugins>
build>
project>
文件名必须是:generatorConfig.xml
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="DB2Tables" targetRuntime="MyBatis3">
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/test_jack"
userId="root"
password="root">
jdbcConnection>
<javaModelGenerator targetPackage="com.jack.generator.entity" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
javaModelGenerator>
<sqlMapGenerator targetPackage="com.jack.generator.mapper" targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER" targetPackage="com.jack.generator.mapper" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
javaClientGenerator>
<table tableName="t_employee" domainObjectName="Employee"/>
<table tableName="t_department" domainObjectName="Department"/>
context>
generatorConfiguration>
eclipse中,项目右键或pom.xml右键,Run As -> Maven build
在弹出的对话框中输入:mybatis-generator:generate
QBC(Quary By Criteria),Criteria是Criterion的复数,译为规则,准则。在SQL语句中相当于查询条件。
QBC查询是将查询条件通过Java对象进行模块化封装。
@Test
public void testGenerator() {
InputStream inputStream = null;
SqlSession sqlSession = null;
try {
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = sqlSessionFactory.openSession(true);
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
// 查询所有数据
List<Employee> list = employeeMapper.selectByExample(null);
list.forEach(System.out::println);
// 根据条件查询
EmployeeExample employeeEexample = new EmployeeExample();
employeeEexample.createCriteria().andEmpNameEqualTo("宋江").andAgeGreaterThanOrEqualTo(20);
employeeEexample.or().andDidIsNotNull();
List<Employee> employees = employeeMapper.selectByExample(employeeEexample);
employees.forEach(System.out::println);
Employee employee = new Employee();
employee.setEid(22L);
employee.setEmpName("林冲");
employee.setGender((byte)1);
employee.setAge(50);
employee.setEmail("[email protected]");
employee.setDid(1L);
employeeMapper.updateByPrimaryKeySelective(employee);
} catch (IOException e) {
e.printStackTrace();
} finally {
sqlSession.close();
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
官网地址:https://pagehelper.github.io/
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>5.3.2version>
dependency>
在MyBatis的核心配置文件中配置PageHelper插件。
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
plugins>
1、在查询功能之前使用PageHelper.startPage(int pageNum, int pageSize)开启分页功能
pageNum:当前页的页码
pageSize:每页显示的条数
@Test
public void testPageHelper(){
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//PageHelper.startPage(2, 2);
Page<Object> page = PageHelper.startPage(2, 4); //print:Page{count=true, pageNum=2, pageSize=4, startRow=4, endRow=8, total=11, pages=3, reasonable=false, pageSizeZero=false}[User [id=6, username=卢俊义, password=1234, age=51, sex=null, [email protected]], User [id=7, username=卢俊义, password=1234, age=51, sex=null, [email protected]], User [id=8, username=宋江, password=songjiang, age=51, sex=null, [email protected]], User [id=9, username=宋江, password=songjiang, age=56, sex=null, [email protected]]]
List<User> users = userMapper.selectAllUser();
//PageInfo page = new PageInfo<>(users, 5); //print:PageInfo{pageNum=1, pageSize=11, size=11, startRow=0, endRow=10, total=11, pages=1, list=[User [id=2, username=宋江, password=songjiang, age=50, sex=null, [email protected]], User [id=3, username=宋江, password=songjiang, age=50, sex=null, [email protected]], User [id=4, username=宋江, password=songjiang, age=51, sex=null, [email protected]], User [id=5, username=卢俊义, password=1234, age=51, sex=null, [email protected]], User [id=6, username=卢俊义, password=1234, age=51, sex=null, [email protected]], User [id=7, username=卢俊义, password=1234, age=51, sex=null, [email protected]], User [id=8, username=宋江, password=songjiang, age=51, sex=null, [email protected]], User [id=9, username=宋江, password=songjiang, age=56, sex=null, [email protected]], User [id=10, username=宋江, password=songjiang, age=56, sex=null, [email protected]], User [id=11, username=宋江, password=songjiang, age=56, sex=null, [email protected]], User [id=12, username=宋江, password=songjiang, age=56, sex=null, [email protected]]], prePage=0, nextPage=0, isFirstPage=true, isLastPage=true, hasPreviousPage=false, hasNextPage=false, navigatePages=5, navigateFirstPage=1, navigateLastPage=1, navigatepageNums=[1]}
users.forEach(System.out::println);
System.out.println(page);
}
输出结果:
age
{
count=true,
pageNum=2,
pageSize=4,
startRow=4,
endRow=8,
total=10,
pages=3,
reasonable=false,
pageSizeZero=false
}
[
User [id=5, username=宋江, password=songjiang, age=51, sex=null, [email protected]],
User [id=6, username=宋江, password=songjiang, age=56, sex=null, [email protected]],
User [id=7, username=宋江, password=songjiang, age=56, sex=null, [email protected]],
User [id=8, username=宋江, password=songjiang, age=56, sex=null, [email protected]]
]
pageNum:当前页码;第几页
pageSize:每页条数
startRow:从第几条开始,不包括startRow
endRow:从第几条结束
total:总条数;共多少条数据
pages:总页数,共多少页
2、在查询获取list集合之后,使用PageInfo pageInfo = new PageInfo<>(List list, int navigatePages)获取分页相关数据
list:分页之后的数据
navigatePages:导航分页的页码数
@Test
public void testPageHelper(){
SqlSession sqlSession = MyBatisUtil.createSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
PageHelper.startPage(3, 3);
//Page
List<User> users = userMapper.selectAllUser();
PageInfo<User> page = new PageInfo<User>(users, 5);
users.forEach(System.out::println);
System.out.println(page);
}
一共10条数据测试
1 4 7 10
2 5 8
3 6 9
PageInfo{
pageNum=3,
pageSize=3,
size=3,
startRow=7,
endRow=9,
total=10,
pages=4,
list=Page{
count=true,
pageNum=3,
pageSize=3,
startRow=6,
endRow=9,
total=10,
pages=4,
reasonable=false,
pageSizeZero=false
}
[
User [id=7, username=宋江, password=songjiang, age=56, sex=null, [email protected]],
User [id=8, username=宋江, password=songjiang, age=56, sex=null, [email protected]],
User [id=9, username=宋江, password=songjiang, age=56, sex=null, [email protected]]
],
prePage=2,
nextPage=4,
isFirstPage=false,
isLastPage=false,
hasPreviousPage=true,
hasNextPage=true,
navigatePages=5,
navigateFirstPage=1,
navigateLastPage=4,
navigatepageNums=[1, 2, 3, 4]
}
一共16条数据测试
1 4 7 10 13 16
2 5 8 11 14
3 6 9 12 15
Page<Object> page = PageHelper.startPage(3, 3); 想显示第3页的3条数据
PageInfo
{
pageNum=3,
pageSize=3,
size=3,
startRow=7,
endRow=9,
total=16,
pages=6,
list=Page
{
count=true,
pageNum=3,
pageSize=3,
startRow=6,
endRow=9,
total=16,
pages=6,
reasonable=false,
pageSizeZero=false
}
[ User [id=7, username=宋江, password=songjiang, age=56, sex=null, [email protected]],
User [id=8, username=宋江, password=songjiang, age=56, sex=null, [email protected]],
User [id=9, username=宋江, password=songjiang, age=56, sex=null, [email protected]]],
prePage=2,
nextPage=4,
isFirstPage=false,
isLastPage=false,
hasPreviousPage=true,
hasNextPage=true,
navigatePages=5,
navigateFirstPage=1,
navigateLastPage=5,
navigatepageNums=[1, 2, 3, 4, 5]
}
常用数据:
pageNum:当前页的页码
pageSize:每页显示的条数
size:当前页显示的真实条数
total:总记录数
pages:总页数
prePage:上一页的页码
nextPage:下一页的页码
isFirstPage/isLastPage:是否为第一页/最后一页
hasPreviousPage/hasNextPage:是否存在上一页/下一页
navigatePages:导航分页的页码数
navigatepageNums:导航分页的页码,[1,2,3,4,5]
/**
* limit index,pageSize
* index:当前页的起始索引
* pageSize:每页显示的条数
* pageNum:当前页的页码
* index=(pageNum-1)*pageSize
*
* 使用MyBatis的分页插件实现分页功能:
* 1、需要在查询功能之前开启分页
* PageHelper.startPage(int pageNum, int pageSize);
* 2、在查询功能之后获取分页相关信息
* PageInfo page = new PageInfo<>(list, 5);
* list表示分页数据
* 5表示当前导航分页的数量
*/
@Test
public void testPageHelper() {
InputStream inputStream = null;
SqlSession sqlSession = null;
try {
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = sqlSessionFactory.openSession(true);
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
//Page
PageHelper.startPage(2, 4);
List<Employee> employees = employeeMapper.selectByExample(null);
PageInfo<Employee> page = new PageInfo<Employee>(employees, 5);
employees.forEach(employee -> System.out.println(employee));
System.out.println("******************");
employees.forEach(System.out::println);
System.out.println("******************");
System.out.println(page);
} catch (IOException e) {
e.printStackTrace();
} finally {
sqlSession.close();
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
问题:
1、‘${}’