title: Mybatis
tag: Mybatis框架
categories: 分类
comment: 是否允许评论(true or false)
description: 描述
top_img: https://z3.ax1x.com/2021/10/06/4xq2s1.png
cover: https://z3.ax1x.com/2021/10/06/4xq2s1.png
Mybatis简介
- Mybatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架
- Mybatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
- Mybatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录
使用Mybatis原因
- Mybatis是一个半自动化的持久化称框架
- JDBC:SQL夹杂Java代码中,耦合度高导致硬编码内伤,维护不易且实际开发需求中sql是有变化,频繁修改的情况多见。
- Hibernate和JPA:长难复杂SQL,对于Hibernate而言处理也不容易,内部自动生成的SQL,不容易做特殊化优化,基于全映射的自动化框架,大量字段的POJO进行部分映射时比较困难。导致数据库性能下降。
- 对于开发人员而言核心SQL还是需要自己优化。
- sql和java编码分开,功能边界清晰,一个专注业务、一个专注数据。
Mybatis-Helloworld
- 创建一个测试表
- 创建对应的javaBean
- 创建mybatis配置文件,sql映射文件
- 测试
Mybatis操作数据库
-
创建Mybatis全局配置文件
mybatis的全局配置文件包含了影响Mybatis行为的设置(Settings)和属性(properties)信息,如数据库连接池信息等。指导着Mybatis进行工作。
-
创建SQL映射文件
映射文件的作用相当于是定义DAO接口的实现类如何工作。
mybaits-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 -->
<mappers>
<mapper resource="EmployeeMapper.xml" />
</mappers>
</configuration>
测试
-
利用全局配置文件,利用SqlSessionFactoryBuilder创建SqlSessionFactory
* 1、接口式编程 * 原生: Dao ====> DaoImpl * mybatis: Mapper ====> xxMapper.xml * 2、SqlSession代表和数据库的一次会话;用完必须关闭; * 3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。 * 4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。 * (将接口和xml进行绑定) * EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMapper.class); * 5、两个重要的配置文件: * mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息 * sql映射文件:保存了每一个sql语句的映射信息: * 将sql抽取出来。
public SqlSessionFactory getSqlSessionFactory() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(inpu tStream); }
-
使用sqlSessionFactory获取sqlSession对象。一个SqlSession对象代表和数据库的一次会话
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession();
接口式编程
employeeMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
<!--
namespace:名称空间;指定为接口的全类名
id:唯一标识
resultType:返回值类型
#{id}:从传递过来的参数中取出id值
public Employee getEmpById(Integer id);
-->
<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee">
select id,last_name lastName,email,gender from tbl_employee where id = #{id}
</select>
</mapper>
定义接口的抽象方法
package com.atguigu.mybatis.dao;
import com.atguigu.mybatis.bean.Employee;
public interface EmployeeMapper {
public Employee getEmpById(Integer id);
}
测试
@Test
public void test01() throws IOException {
// 1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
// 2、获取sqlSession对象
SqlSession openSession = sqlSessionFactory.openSession();
try {
// 3、获取接口的实现类对象
// 会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.getEmpById(1);
System.out.println(mapper.getClass());
System.out.println(employee);
} finally {
openSession.close();
}
}
- 创建一个接口(EmployeeMapper.java),其中定义抽象方法
- 将EmployeeMapper.xml中的namesapce改为接口的全类名
- 将标签中的"id"改为与接口中定义的抽象方法相同的方法名
- 第2,3步实现了动态绑定,在标签中写方法的具体实现
- 在测试方法中不需要创建接口的实现类,mybatis会为接口自动创建一个代理对象去执行增删改查方法。
sqlsession
SqlSession的实例不是线程安全的,因此式是不能被共享的
SqlSession每次使用完成后需要正确关闭,这个关闭操作时必须的
SqlSession可以直接调用方法的id进行数据库操作,但是我们一般还是推荐使用SqlSession获取到Dao接口的代理类,执行代理对象的方法,可以更安全的进行类型检查。
作用域和生命周期
SqlsessionFactoryBuilder
这个类可以被实例化、使用和丢弃,一旦创建了SqlSessionFactory,就不再需要它。因此SqlSessionFactoryBuilder实例的最佳作用域是方法作用域。你可以重用SqlSessionFactoryBuilder来创建多个SqlSessionFactory实例。
SqlSessionFactory
SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或者创建另一个实例。使用SqlSessionFactory的最佳实践时在应用运行期间不需要重复创建多次,多次重建SqlSessionFactory被视为一种“坏习惯”。因此SqlSessionFactory的最佳作用域是应用作用域。可以使用单例模式或者静态单例模式可以做到。
SqlSession
每个线程都应该有自己的SqlSession实例。SqlSession的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。绝对不能将SqlSession实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。
Mybatis-全局配置文件(mybatis-config.xml)
Mybatis的配置文件包含了会深深影响Mybatis行为的设置和属性信息,
properties属性
dbconfig.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=123456
mybatis-config.xml
<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>
<!--
1、mybatis可以使用properties来引入外部properties配置文件的内容;
resource:引入类路径下的资源
url:引入网络路径或者磁盘路径下的资源
-->
<properties resource="dbconfig.properties"></properties>
settings(设置)
mybatis中极为重要的调整设置,它们会改变Mybatis的运行时行为。
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 | true | false | false |
aggressiveLazyLoading | 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods )。 | true | false | false (在 3.4.1 及之前的版本中默认为 true) |
multipleResultSetsEnabled | 是否允许单个语句返回多结果集(需要数据库驱动支持)。 | true | false | true |
useColumnLabel | 使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察。 | true | false | true |
useGeneratedKeys | 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)。 | true | false | False |
autoMappingBehavior | 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。 | NONE, PARTIAL, FULL | PARTIAL |
autoMappingUnknownColumnBehavior | 指定发现自动映射目标未知列(或未知属性类型)的行为。NONE : 不做任何反应WARNING : 输出警告日志('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARN )FAILING : 映射失败 (抛出 SqlSessionException ) | NONE, WARNING, FAILING | NONE |
defaultExecutorType | 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(PreparedStatement); BATCH 执行器不仅重用语句还会执行批量更新。 | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定数据库驱动等待数据库响应的秒数。 | 任意正整数 | 未设置 (null) |
defaultFetchSize | 为驱动的结果集获取数量(fetchSize)设置一个建议值。此参数只可以在查询设置中被覆盖。 | 任意正整数 | 未设置 (null) |
defaultResultSetType | 指定语句默认的滚动策略。(新增于 3.5.2) | FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未设置) | 未设置 (null) |
safeRowBoundsEnabled | 是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。 | true | false | False |
safeResultHandlerEnabled | 是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。 | true | false | True |
mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | true | false | False |
localCacheScope | MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。 | SESSION | STATEMENT | SESSION |
jdbcTypeForNull | 当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型。 某些数据库驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 | JdbcType 常量,常用值:NULL、VARCHAR 或 OTHER。 | OTHER |
lazyLoadTriggerMethods | 指定对象的哪些方法触发一次延迟加载。 | 用逗号分隔的方法列表。 | equals,clone,hashCode,toString |
defaultScriptingLanguage | 指定动态 SQL 生成使用的默认脚本语言。 | 一个类型别名或全限定类名。 | org.apache.ibatis.scripting.xmltags.XMLLanguageDriver |
defaultEnumTypeHandler | 指定 Enum 使用的默认 TypeHandler 。(新增于 3.4.5) | 一个类型别名或全限定类名。 | org.apache.ibatis.type.EnumTypeHandler |
callSettersOnNulls | 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这在依赖于 Map.keySet() 或 null 值进行初始化时比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的。 | true | false | false |
returnInstanceForEmptyRow | 当返回行的所有列都是空时,MyBatis默认返回 null 。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集(如集合或关联)。(新增于 3.4.2) | true | false | false |
logPrefix | 指定 MyBatis 增加到日志名称的前缀。 | 任何字符串 | 未设置 |
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J(deprecated since 3.5.9) | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
proxyFactory | 指定 Mybatis 创建可延迟加载对象所用到的代理工具。 | CGLIB | JAVASSIST | JAVASSIST (MyBatis 3.3 以上) |
vfsImpl | 指定 VFS 的实现 | 自定义 VFS 的实现的类全限定名,以逗号分隔。 | 未设置 |
useActualParamName | 允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1) | true | false | true |
configurationFactory | 指定一个提供 Configuration 实例的类。 这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 这个类必须包含一个签名为static Configuration getConfiguration() 的方法。(新增于 3.2.3) | 一个类型别名或完全限定类名。 | 未设置 |
shrinkWhitespacesInSql | 从SQL中删除多余的空格字符。请注意,这也会影响SQL中的文字字符串。 (新增于 3.5.5) | true | false | false |
defaultSqlProviderType | Specifies an sql provider class that holds provider method (Since 3.5.6). This class apply to the type (or value ) attribute on sql provider annotation(e.g. @SelectProvider ), when these attribute was omitted. | A type alias or fully qualified class name | Not set |
nullableOnForEach | Specifies the default value of ‘nullable’ attribute on ‘foreach’ tag. (Since 3.5.9) | true | false | false |
<!--
2、settings包含很多重要的设置项
setting:用来设置每一个设置项
name:设置项名
value:设置项取值
-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
类型别名(typeAliases)
类型别名时Java类型设置一个短的名字,可以方便我们引用某个类。
<typeAliases>
<!-- 1、typeAlias:为某个java类型起别名
type:指定要起别名的类型全类名;默认别名就是类名小写;employee
alias:指定新的别名
-->
<typeAlias type="com.atguigu.mybatis.bean.Employee" alias="emp"/>
<!-- 2、package:为某个包下的所有类批量起别名
name:指定包名(为当前包以及下面所有的后代包的每一个类都起一个默认别名(类名小写),)
-->
<package name="com.atguigu.mybatis.bean"/>
<!-- 3、批量起别名的情况下,使用@Alias注解为某个类型指定新的别名 -->
</typeAliases>
@Alias("emp")
public class Employee {
需要注意的是,Mybatis已经为许多常见的Java类型内建立了相应的类型别名。它们都是大小写不敏感的,我们在起别名的时候千万不要占用已有的别名。
别名 | 映射的类型 |
---|---|
_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 |
插件(plugins)
Mybatis允许你在映射语句执行过程中的某一点进行拦截。默认情况下,Mybatis允许使用插件来拦截的方法调用包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query
在这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看mybatis的源代码。如果你想做的不仅仅是监控方法的调用,那么最好了解重写方法的行为。因为在试图修改和重写已有方法的行为时,很可能会破坏Mybatis的核心模块。这些都是更底层的类和方法,所以使用插件的时候要特别当心。
通过Mybatis提供的强大机制,使用插件时非常简单的,只需要实现Interceptor接口,并指定想要拦截的方法签名即可。
// ExamplePlugin.java
@Intercepts({@Signature(
type= Executor.class,
method = "update",
args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
private Properties properties = new Properties();
public Object intercept(Invocation invocation) throws Throwable {
// implement pre processing if need
Object returnObject = invocation.proceed();
// implement post processing if need
return returnObject;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
<!-- mybatis-config.xml -->
<plugins>
<plugin interceptor="org.mybatis.example.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>
上面的插件将会拦截Executor实例中所有的"update"方法调用,这里的Executor时负责执行底层映射语句的内部对象。
覆盖配置类
除了用插件来修改Mybatis核心行为以外,还可以通过完全覆盖配置类来达到目的。只需要继承配置类后覆盖其中的某个方法,再把它传递到SqlSessionFactoryBuilder.build(myconfig)方法即可。再次重申,这可能会极大影响Mybatis的行为,勿请慎之又慎。
环境配置(envoronments)
Mybatis可以配置成适应多种环境,这种机制有助于将SQL映射应用于多种数据库之中,现实情况下有多种理由需要这么做,如,开发、测试和生产环境需要有不同的配置。
不过要记住:尽管可以配置多个环境,但每个SqlSessionFactory实例只能选择一种环境。
所以如果需要连接两个数据库,就需要创建两个SqlSesstionFactory实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依次类推,记起来很简单:
- 每个数据库对应一个SqlSessionFactory实例
为了指定创建哪种环境,只要将它作为可选的参数传递给SqlSessionFactoryBuilder即可。可以接受环境配置的两个方法签名是:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
如果忽略了环境参数,那么将会加载默认环境,如下所示:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);
environments元素定义了如何配置环境。
<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>
注意一些点:
- 默认使用的环境ID(比如:default= “development”)
- 每个environment元素定义的环境ID
- 事务管理器的配置
- 数据源的配置
默认环境和环境ID顾名思义。环境可以随意命名,但务必保证默认的环境ID要匹配其中一个环境ID.
事务管理器
在mybatis中有两种类型的事务管理器(type="[JDBC|MANAGED]");
-
JDBC-这个配置直接使用了JDBC的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
-
MANAGED-这个配置几乎什么也不做。它从不提交或回滚一个连接,而是让容器来管理事务的整个周期。默认情况下它会关闭连接,然而一些容器并不希望被关闭,因此需要将closeConnection属性设置为false来阻止默认的关闭行为。例如:
<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>
如果你正在使用Spring+Mybatis,则没有必要配置事务管理器,因为Spring模块会使用自带的管理器来覆盖前面的配置。
这两种事务管理器类型都不需要设置任何属性。它们其实是类型别名,换句话说,你可以用TransactionFactory接口实现类的全限定名或类型别名代替它们。
public interface TransactionFactory {
default void setProperties(Properties props) { // 从 3.5.2 开始,该方法为默认方法
// 空实现
}
Transaction newTransaction(Connection conn);
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}
在事务管理器实例化后,所有在XML种配置的属性将会被传递给setProperties()方法。你的实现还需要创建一个Transaction接口的实现类,这个接口如下:
public interface Transaction {
Connection getConnection() throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
Integer getTimeout() throws SQLException;
}
使用这两个接口,可以完全自定义Mybatis对事务的处理。
数据源(dataSource)
dataSource元素使用标准的JDBC数据源接口来配置JDBC连接对象的资源。
有三种内建的数据源类型(type="[UNPOOLED|POOLED|JNDI]"):
UNPOOLED
这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接的可用性要求不高的简单应用程序来说,是一个很好的选择。性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合。
UNPOOLED 类型的数据源仅仅需要配置以下 5 种属性:
driver
– 这是 JDBC 驱动的 Java 类全限定名(并不是 JDBC 驱动中可能包含的数据源类)。url
– 这是数据库的 JDBC URL 地址。username
– 登录数据库的用户名。password
– 登录数据库的密码。defaultTransactionIsolationLevel
– 默认的连接事务隔离级别。defaultNetworkTimeout
– 等待数据库操作完成的默认网络超时时间(单位:毫秒)。查看java.sql.Connection#setNetworkTimeout()
的 API 文档以获取更多信息。
作为可选项,你也可以传递属性给数据库驱动。只需在属性名加上“driver.”前缀即可,例如:
driver.encoding=UTF8
这将通过 DriverManager.getConnection(url, driverProperties) 方法传递值为 UTF8
的 encoding
属性给数据库驱动。
POOLED
这种数据源的实现利用“池”的概念将JDBC连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。这种处理方式很流行,能使并发web应用快速响应请求。
poolMaximumActiveConnections
– 在任意时间可存在的活动(正在使用)连接数量,默认值:10poolMaximumIdleConnections
– 任意时间可能存在的空闲连接数。poolMaximumCheckoutTime
– 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)poolTimeToWait
– 这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败且不打印日志),默认值:20000 毫秒(即 20 秒)。poolMaximumLocalBadConnectionTolerance
– 这是一个关于坏连接容忍度的底层设置, 作用于每一个尝试从缓存池获取连接的线程。 如果这个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接,但是这个重新尝试的次数不应该超过poolMaximumIdleConnections
与poolMaximumLocalBadConnectionTolerance
之和。 默认值:3(新增于 3.4.5)poolPingQuery
– 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动出错时返回恰当的错误消息。poolPingEnabled
– 是否启用侦测查询。若开启,需要设置poolPingQuery
属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false。poolPingConnectionsNotUsedFor
– 配置 poolPingQuery 的频率。可以被设置为和数据库连接超时时间一样,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)。
JNDI
这个数据源实现是为了能在如EJB或应用服务器这类容器中使用,容器以集中或在外部配置数据源,然后放置一个JNDI上下文的数据源引用。这种数据源配置只需要两个属性:
initial_context
– 这个属性用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,如果忽略,那么将会直接从 InitialContext 中寻找 data_source 属性。data_source
– 这是引用数据源实例位置的上下文路径。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。
数据库厂商标识
Mybatis可以根据不同的数据库厂商执行不同的语句。这种多厂商的支持是基于映射语句中的databaseId属性。
<!-- 5、databaseIdProvider:支持多数据库厂商的;
type="DB_VENDOR":VendorDatabaseIdProvider
作用就是得到数据库厂商的标识(驱动getDatabaseProductName()),mybatis就能根据数据库厂商标识来执行不同的sql;
MySQL,Oracle,SQL Server,xxxx
-->
<databaseIdProvider type="DB_VENDOR">
<!-- 为不同的数据库厂商起别名 -->
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
<property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>
-
Type:DB_VENDOR
使用Mybatis提供的VendorDatabasedProvider解析数据库厂商标识。也可以实现DatabaseIdProvider接口来定义。
-
Property-name:数据库厂商标识
-
Property-value:为标识起一个别名,方便SQL语句使用databaseId属性引用
<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee"
databaseId="mysql">
select * from tbl_employee where id = #{id}
</select>
Mybatis匹配规则如下:
- 如果没有配置databaseIdProvider标签,那么databaseId=null
- 如果配置了databaseIdProvider标签,使用标签配置的name去匹配数据库信息,匹配上设置databaseId=配置指定的值,否则依旧为null。
- 如果databaseId不为null,他只会找到配置databaseId的sql语句
- Mybatis会加载不带databaseId属性和带有匹配当前数据库databaseId属性的所有语句。如果同时找到带有databaseId和不带databaseId的相同语句,则后者会被抛弃。
映射器(mappers)
- mapper逐个注册SQL映射文件
<!-- 使用相对于类路径的资源引用 -->
<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="com.atguigu.dao"/>
</mappers>
Mybatis-XML映射文件
映射文件指导着Mybatis如何进行数据库增删改查,有着非常重要的意义。
select
查询语句是Mybatis中最常用的元素之一。
<!--
namespace:名称空间;指定为接口的全类名
id:唯一标识
resultType:返回值类型
#{id}:从传递过来的参数中取出id值
public Employee getEmpById(Integer id);
-->
<select id="getEmpById" paramterType = "int"resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee where id = #{id}
</select>
这个语句名为getEmpById,接受一个int类型的参数,并返回一个Employee类型的对象
select元素的属性
属性 | 描述 |
---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType | 将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
resultType | 期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。 |
resultMap | 对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。 |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。 |
useCache | 将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。 |
fetchSize | 这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)。 |
statementType | 可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
resultSetType | FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)。 |
databaseId | 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。 |
resultOrdered | 这个设置仅针对嵌套结果 select 语句:如果为 true,将会假设包含了嵌套结果集或是分组,当返回一个主结果行时,就不会产生对前面结果集的引用。 这就使得在获取嵌套结果集的时候不至于内存不够用。默认值:false 。 |
resultSets | 这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。 |
insert、update、delete
<!-- public void addEmp(Employee employee); -->
<!-- parameterType:参数类型,可以省略,
获取自增主键的值:
mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys();
useGeneratedKeys="true";使用自增主键获取主键值策略
keyProperty;指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性
-->
<insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee"
useGeneratedKeys="true" keyProperty="id" databaseId="mysql">
insert into tbl_employee(last_name,email,gender)
values(#{lastName},#{email},#{gender})
</insert>
<!-- public void updateEmp(Employee employee); -->
<update id="updateEmp">
update tbl_employee
set last_name=#{lastName},email=#{email},gender=#{gender}
where id=#{id}
</update>
<!-- public void deleteEmpById(Integer id); -->
<delete id="deleteEmpById">
delete from tbl_employee where id=#{id}
</delete>
元素属性
属性 | 描述 |
---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType | 将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
parameterMap | 用于引用外部 parameterMap 的属性,目前已被废弃。请使用行内参数映射和 parameterType 属性。 |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。 |
statementType | 可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
useGeneratedKeys | (仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。 |
keyProperty | (仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset )。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
keyColumn | (仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
databaseId | 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。 |
插入语句的规则更加丰富,在插入语句里面有一些额外的属性和子元素用来处理主键的生成,并且提供了多种生成方式。
首先,如果你的数据库支持自动生成主键的字段,那么你可以将useGeneratedKeys=”true”,然后再把 keyProperty 设置为目标属性就 OK 了。如下所示:
<insert id="insertAuthor" useGeneratedKeys="true"
keyProperty="id">
insert into Author (username,password,email,bio)
values (#{username},#{password},#{email},#{bio})
</insert>
如果你的数据库还支持多行插入,你可以传入一个Author数组或集合。
<insert id="insertAuthor" useGeneratedKeys="true"
keyProperty="id">
insert into Author (username, password, email, bio) values
<foreach item="item" collection="list" separator=",">
(#{item.username}, #{item.password}, #{item.email}, #{item.bio})
</foreach>
</insert>
对于不支持自动生成主键列的数据库和可能不支持自动生成主键的JDBC驱动,Mybatis有另外一种方法来生成主键。
<insert id="insertAuthor">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
</selectKey>
insert into Author
(id, username, password, email,bio, favourite_section)
values
(#{id}, #{username}, #{password}, #{email}, #{bio}, #{favouriteSection,jdbcType=VARCHAR})
</insert>
selectKey元素的属性
属性 | 描述 |
---|---|
keyProperty | selectKey 语句结果应该被设置到的目标属性。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
keyColumn | 返回结果集中生成列属性的列名。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
resultType | 结果的类型。通常 MyBatis 可以推断出来,但是为了更加准确,写上也不会有什么问题。MyBatis 允许将任何简单类型用作主键的类型,包括字符串。如果生成列不止一个,则可以使用包含期望属性的 Object 或 Map。 |
order | 可以设置为 BEFORE 或 AFTER 。如果设置为 BEFORE ,那么它首先会生成主键,设置 keyProperty 再执行插入语句。如果设置为 AFTER ,那么先执行插入语句,然后是 selectKey 中的语句 - 这和 Oracle 数据库的行为相似,在插入语句内部可能有嵌入索引调用。 |
statementType | 和前面一样,MyBatis 支持 STATEMENT ,PREPARED 和 CALLABLE 类型的映射语句,分别代表 Statement , PreparedStatement 和 CallableStatement 类型。 |
参数
对于大多数简单的使用场景,你都不需要使用复杂的参数,如:
<select id="selectUsers" resultType="User">
select id, username, password
from users
where id = #{id}
</select>
对于参数类型(paramterType)会被自动设置为int,这个参数可以随意命名。原始类型或简单数据类型因为没有其他属性,会用它们的值作为参数。然而,如果传入一个复杂的对象,行为就会有点不一样了。如:
<insert id="insertUser" parameterType="User">
insert into users (id, username, password)
values (#{id}, #{username}, #{password})
</insert>
如果User类型的参数对象传递到了语句中,会查找id、username和password属性,然后将它们的值传入预处理语句的参数中。
字符串转换
默认情况下,使用#{}参数语法时,Mybatis会创建PreparedStatement参数占位符,并通过占位符安全地设置参数(就像使用?一样)。这样做更安全,更迅速,通常也是首选做法,不过有时你想直接在SQL语句中直接插入一个不转义的字符串。
当SQL语句中的元数据(如表名或列名)是动态生成的时候,字符串替换将会非常有用。如果你想select一个表任意一列的数据时,不需要这样写:
@Select("select * from user where id = #{id}")
User findById(@Param("id") long id);
@Select("select * from user where name = #{name}")
User findByName(@Param("name") String name);
@Select("select * from user where email = #{email}")
User findByEmail(@Param("email") String email);
// 其它的 "findByXxx" 方法
而是只写这样一个方法:
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);
其中${column}会被直接替换,而#{value}会使用?预处理。这样,就能完成同样的任务:
User userOfId1 = userMapper.findByColumn("id", 1L);
User userOfNameKid = userMapper.findByColumn("name", "kid");
User userOfEmail = userMapper.findByColumn("email", "noone@nowhere.com");
结果映射
result元素时Mybatis中最重要最强大的元素。它可以让你从90%的JDBCResultType数据提取代码中解放出来,并在一些情形下允许你进行一些JDBC不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份resultMap能够代替实现同等功能的数千行代码。ResultMap的设计思想是,对简单的语句做到零配置,对于复杂的语句,只需要描述语句之间的关系就行了。
一个简单的没有resultMap类型的语句:
<select id="selectUsers" resultType="map">
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
上述语句只是简单地将所有的列映射到HashMap的键上,这由resultType属性指定。虽然在大部分情况下是都够用的,但是HashMap并不是一个很好的领域模型。你的程序更可能会使用JavaBean或者POJO作为领域模型。
package com.someapp.model;
public class User {
private int id;
private String username;
private String hashedPassword;
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 getHashedPassword() {
return hashedPassword;
}
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
}
基于 JavaBean 的规范,上面这个类有 3 个属性:id,username 和 hashedPassword。这些属性会对应到 select 语句中的列名。
这样的一个 JavaBean 可以被映射到 ResultSet
,就像映射到 HashMap
一样简单。
<select id="selectUsers" resultType="com.someapp.model.User">
select id, username, hashedPassword
from some_table
where id = #{id}
</select
显示的使用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>
然后再引用它的语句中设置resultMap属性就行了。如:
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
高级结果映射
例如下面一个复杂的语句:
<!-- 非常复杂的语句 -->
<select id="selectBlogDetails" resultMap="detailedBlogResultMap">
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
A.id as author_id,
A.username as author_username,
A.password as author_password,
A.email as author_email,
A.bio as author_bio,
A.favourite_section as author_favourite_section,
P.id as post_id,
P.blog_id as post_blog_id,
P.author_id as post_author_id,
P.created_on as post_created_on,
P.section as post_section,
P.subject as post_subject,
P.draft as draft,
P.body as post_body,
C.id as comment_id,
C.post_id as comment_post_id,
C.name as comment_name,
C.comment as comment_text,
T.id as tag_id,
T.name as tag_name
from Blog B
left outer join Author A on B.author_id = A.id
left outer join Post P on B.id = P.blog_id
left outer join Comment C on P.id = C.post_id
left outer join Post_Tag PT on PT.post_id = P.id
left outer join Tag T on PT.tag_id = T.id
where B.id = #{id}
</select>
对应的复杂结果映射
!-- 非常复杂的结果映射 -->
<resultMap id="detailedBlogResultMap" type="Blog">
<constructor>
<idArg column="blog_id" javaType="int"/>
</constructor>
<result property="title" column="blog_title"/>
<association property="author" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
<result property="password" column="author_password"/>
<result property="email" column="author_email"/>
<result property="bio" column="author_bio"/>
<result property="favouriteSection" column="author_favourite_section"/>
</association>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<association property="author" javaType="Author"/>
<collection property="comments" ofType="Comment">
<id property="id" column="comment_id"/>
</collection>
<collection property="tags" ofType="Tag" >
<id property="id" column="tag_id"/>
</collection>
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>
</collection>
</resultMap>
一一来解开这个面纱
-
constructor
- 用于在实例化类时,注入结果到构造方法中
idArg
- ID 参数;标记出作为 ID 的结果可以帮助提高整体性能arg
- 将被注入到构造方法的一个普通结果
-
id
– 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能 -
result
– 注入到字段或 JavaBean 属性的普通结果 -
association
– 一个复杂类型的关联;许多结果将包装成这种类型
- 嵌套结果映射 – 关联可以是
resultMap
元素,或是对其它结果映射的引用
- 嵌套结果映射 – 关联可以是
-
collection
– 一个复杂类型的集合
- 嵌套结果映射 – 集合可以是
resultMap
元素,或是对其它结果映射的引用
- 嵌套结果映射 – 集合可以是
-
discriminator
– 使用结果值来决定使用哪个
resultMap
-
case
– 基于某些值的结果映射
- 嵌套结果映射 –
case
也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射
- 嵌套结果映射 –
-
ResultMap的属性列表
属性 | 描述 |
---|---|
id | 当前命名空间中的一个唯一标识,用于标识一个结果映射。 |
type | 类的完全限定名, 或者一个类型别名(关于内置的类型别名,可以参考上面的表格)。 |
autoMapping | 如果设置这个属性,MyBatis 将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset) |
id&result
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
这些元素是结果映射的基础。id和result元素都将一个列的值映射到一个简单的数据类型的属性或字段。
这两者之间唯一不同的是,id元素对应的属性会被标记为对象昂的标识符,在比较对象实例时使用。
id和result的属性
属性 | 描述 |
---|---|
property | 映射到列结果的字段或属性。如果 JavaBean 有这个名字的属性(property),会先使用该属性。否则 MyBatis 将会寻找给定名称的字段(field)。 无论是哪一种情形,你都可以使用常见的点式分隔形式进行复杂属性导航。 比如,你可以这样映射一些简单的东西:“username”,或者映射到一些复杂的东西上:“address.street.number”。 |
column | 数据库中的列名,或者是列的别名。一般情况下,这和传递给 resultSet.getString(columnName) 方法的参数一样。 |
javaType | 一个 Java 类的全限定名,或一个类型别名(关于内置的类型别名,可以参考上面的表格)。 如果你映射到一个 JavaBean,MyBatis 通常可以推断类型。然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与期望的相一致。 |
jdbcType | JDBC 类型,所支持的 JDBC 类型参见这个表格之后的“支持的 JDBC 类型”。 只需要在可能执行插入、更新和删除的且允许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 编程,你需要对可以为空值的列指定这个类型。 |
typeHandler | 我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默认的类型处理器。 这个属性值是一个类型处理器实现类的全限定名,或者是类型别名。 |
支持的JDBC类型
Mybatis通过内置的jdbcType枚举类型支持下面的JDBC类型。
BIT | FLOAT | CHAR | TIMESTAMP | OTHER | UNDEFINED |
---|---|---|---|---|---|
TINYINT | REAL | VARCHAR | BINARY | BLOB | NVARCHAR |
SMALLINT | DOUBLE | LONGVARCHAR | VARBINARY | CLOB | NCHAR |
INTEGER | NUMERIC | DATE | LONGVARBINARY | BOOLEAN | NCLOB |
BIGINT | DECIMAL | TIME | NULL | CURSOR | ARRAY |
构造方法
通过修改对象属性的方式,可以满足大多数的数据传输对象以及绝大部分领域模型的要求。但是有些情况下你想使用不可变的类。一般来说,很少改变或基本不变的包含引用或数据的表,很适合使用不可变类。构造方法注入允许你在初始化时为类设置属性的值,而不用暴露共有方法。Mybatis也支持私有属性和私有JavaBean属性来完成注入,但有一些人更青睐于通过构造方法注入。constructor元素就是为此而生的。
下面看这个构造方法:
public class User {
//...
public User(Integer id, String username, int age) {
//...
}
//...
}
为了将结果注入构造方法,Mybatis需要通过某种定位方式定位相应的构造方法。在下面的例子中,MyBatis 搜索一个声明了三个形参的构造方法,参数类型以 java.lang.Integer
, java.lang.String
和 int
的顺序给出。
<constructor>
<idArg column="id" javaType="int"/>
<arg column="username" javaType="String"/>
<arg column="age" javaType="_int"/>
</constructor>
属性 | 描述 |
---|---|
column | 数据库中的列名,或者是列的别名。一般情况下,这和传递给 resultSet.getString(columnName) 方法的参数一样。 |
javaType | 一个 Java 类的完全限定名,或一个类型别名(关于内置的类型别名,可以参考上面的表格)。 如果你映射到一个 JavaBean,MyBatis 通常可以推断类型。然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与期望的相一致。 |
jdbcType | JDBC 类型,所支持的 JDBC 类型参见这个表格之前的“支持的 JDBC 类型”。 只需要在可能执行插入、更新和删除的且允许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 编程,你需要对可能存在空值的列指定这个类型。 |
typeHandler | 我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默认的类型处理器。 这个属性值是一个类型处理器实现类的完全限定名,或者是类型别名。 |
select | 用于加载复杂类型属性的映射语句的 ID,它会从 column 属性中指定的列检索数据,作为参数传递给此 select 语句。具体请参考关联元素。 |
resultMap | 结果映射的 ID,可以将嵌套的结果集映射到一个合适的对象树中。 它可以作为使用额外 select 语句的替代方案。它可以将多表连接操作的结果映射成一个单一的 ResultSet 。这样的 ResultSet 将会将包含重复或部分数据重复的结果集。为了将结果集正确地映射到嵌套的对象树中,MyBatis 允许你 “串联”结果映射,以便解决嵌套结果集的问题。想了解更多内容,请参考下面的关联元素。 |
name | 构造方法形参的名字。从 3.4.3 版本开始,通过指定具体的参数名,你可以以任意顺序写入 arg 元素。参看上面的解释。 |
discriminator鉴别器
可以用来判断某列的值,然后自定义根据得到某列的不同值做出不同的封装行为
<!-- discriminator:鉴别器,可以用来判断某列的值,然后根据某列的值改变封装行为
假设:
如果查询结果是女性,则把部门信息查询出来,否则不查询
如果是男性,把last_name这一列的值赋值给email
-->
<resultMap type="com.bean.Employee" id="MyEmpDis">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<association property="dept"
select="com.dao.DepartmentMapper.getDeptById"
column="d_id">
</association>
<!--
column:指定要判断的列名
javaType:列值对应的java类型
-->
<discriminator javaType="string" column="gender">
<!-- 女生 -->
<!-- resultType不可缺少,也可以使用resutlMap -->
<case value="0" resultType="com.bean.Employee">
<association property="dept"
select="com.dao.DepartmentMapper.getDeptById"
column="d_id">
</association>
</case>
<!-- 男生 -->
<case value="1" resultType="com.bean.Employee">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="last_name" property="email"/>
<result column="gender" property="gender"/>
</case>
</discriminator>
</resultMap>
关联
<association property="author" column="blog_author_id" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
</association>
在我们的示例中,一个博客有一个用户。关联结果映射和其他类型的映射工作方式差不多。你需要指定目标属性名以及属性的javaType。
关联的不同之处是,你需要告诉Mybatis如何进行加载关联。Mybatis有两种不同的方式加载关联:
- 嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。
- 嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集
关联嵌套的Select查询
属性 | 描述 |
---|---|
column | 数据库中的列名,或者是列的别名。一般情况下,这和传递给 resultSet.getString(columnName) 方法的参数一样。 注意:在使用复合主键的时候,你可以使用 column="{prop1=col1,prop2=col2}" 这样的语法来指定多个传递给嵌套 Select 查询语句的列名。这会使得 prop1 和 prop2 作为参数对象,被设置为对应嵌套 Select 语句的参数。 |
select | 用于加载复杂类型属性的映射语句的 ID,它会从 column 属性指定的列中检索数据,作为参数传递给目标 select 语句。 具体请参考下面的例子。注意:在使用复合主键的时候,你可以使用 column="{prop1=col1,prop2=col2}" 这样的语法来指定多个传递给嵌套 Select 查询语句的列名。这会使得 prop1 和 prop2 作为参数对象,被设置为对应嵌套 Select 语句的参数。 |
fetchType | 可选的。有效值为 lazy 和 eager 。 指定属性后,将在映射中忽略全局配置参数 lazyLoadingEnabled ,使用属性的值。 |
示例:
<resultMap id="blogResult" type="Blog">
<association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>
<select id="selectBlog" resultMap="blogResult">
SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id="selectAuthor" resultType="Author">
SELECT * FROM AUTHOR WHERE ID = #{id}
</select>
一个用来加载博客,另外一个用来加载作者。而且博客的结果映射描述了应用使用selectAuthor语句加载author属性。
集合
<collection property="posts" ofType="domain.blog.Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<result property="body" column="post_body"/>
</collection>
集合元素和关联元素几乎是一样的,它们相似程度很高。
每个部门有多个员工,即在部门中员工是一个集合属性
使用collection嵌套封装结果集
collection定义关联的集合
ofType:指定集合里的元素类型
<resultMap type="com.bean.Department" id="MyDept">
...
<collection property="emps" ofType="com.bean.Employee">
<!-- 定义这个集合中元素的封装规则 -->
<id column="eid" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
</collection>
</resultMap>
使用collection进行分步查询、延迟加载与association类似
扩展
要是在使用association或者collection时需要将多个列的值传递给调用的方法,可以将多列的值封装到map中进行传递column="{key1 = column1, key2 = column2}"
被调用的方法
<select id="getEmpsByDeptId" resultMap="xxx">
select xxx from tbl_employee where id = #{deptId}
</select>
调用该方法的xml文件中:
<collection property="emps" select="com.dao.EmployeeMapperPlus.getEmpsByDeptId"
column="{deptId = id}">
</collection>
即使全局开启了延迟加载,仍然可以在association或者collection标签中修改fetchType的值来开启或关闭延迟加载。
动态SQL
动态SQL是Mybatis的强大特性之一。如果你使用过JDBC或其他类似的框架,你应该能理解根据不同条件拼接SQL语句有多痛苦。
if
使用动态SQL最常见的情景是根据条件包含where子句的一部分。如:
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
如果希望通过“title”和“author”两个参数进行可选搜索怎么办呢?
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select
choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,Mybatis提供了choose元素,有点像java中的switch语句。
<!-- public List<Employee> getEmpsByConditionChoose(Employee employee); -->
<select id="getEmpsByConditionChoose" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee
<where>
<!-- 如果带了id就用id查,如果带了lastName就用lastName查;只会进入其中一个 -->
<choose>
<when test="id!=null">
id=#{id}
</when>
<when test="lastName!=null">
last_name like #{lastName}
</when>
<when test="email!=null">
email = #{email}
</when>
<otherwise>
gender = 0
</otherwise>
</choose>
</where>
</select>
trim、where、set
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
where元素只会在子元素返回任何内容的情况下才插入“WHERE”子句。而且,若子句的开头为AND或OR,where元素也会将它们去除。
如果where元素与你期望的不太一样,你也可以通过自定义trim元素来定制where元素的功能。如
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
prefixOverrides属性会忽略通过管道符分割的文本序列。上述例子会移除所有prefixOverrides属性中指定的内容,并且插入prefix属性中指定的内容。
<!--public List<Employee> getEmpsByConditionTrim(Employee employee); -->
<select id="getEmpsByConditionTrim" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee
<!-- 后面多出的and或者or where标签不能解决
prefix="":前缀:trim标签体中是整个字符串拼串 后的结果。
prefix给拼串后的整个字符串加一个前缀
prefixOverrides="":
前缀覆盖: 去掉整个字符串前面多余的字符
suffix="":后缀
suffix给拼串后的整个字符串加一个后缀
suffixOverrides=""
后缀覆盖:去掉整个字符串后面多余的字符
-->
<!-- 自定义字符串的截取规则 -->
<trim prefix="where" suffixOverrides="and">
<if test="id!=null">
id=#{id} and
</if>
<if test="lastName!=null && lastName!=""">
last_name like #{lastName} and
</if>
<if test="email!=null and email.trim()!=""">
email=#{email} and
</if>
<!-- ognl会进行字符串与数字的转换判断 "0"==0 -->
<if test="gender==0 or gender==1">
gender=#{gender}
</if>
</trim>
</select>
用于动态更新语句的类似解决方案叫做set,set元素可以用于动态包含需要更新的列,忽略其他不更新的列。
<!--public void updateEmp(Employee employee); -->
<update id="updateEmp">
<!-- Set标签的使用 -->
update tbl_employee
<set>
<if test="lastName!=null">
last_name=#{lastName},
</if>
<if test="email!=null">
email=#{email},
</if>
<if test="gender!=null">
gender=#{gender}
</if>
</set>
where id=#{id}
</update>
foreach
动态SQL的另一个常见使用场景是对集合进行遍历,如:
<!--public List<Employee> getEmpsByConditionForeach(List<Integer> ids); -->
<select id="getEmpsByConditionForeach" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee
<!--
collection:指定要遍历的集合:
list类型的参数会特殊处理封装在map中,map的key就叫list
item:将当前遍历出的元素赋值给指定的变量
separator:每个元素之间的分隔符
open:遍历出所有结果拼接一个开始的字符
close:遍历出所有结果拼接一个结束的字符
index:索引。遍历list的时候是index就是索引,item就是当前值
遍历map的时候index表示的就是map的key,item就是map的值
#{变量名}就能取出变量的值也就是当前遍历出的元素
-->
<foreach collection="ids" item="item_id" separator=","
open="where id in(" close=")">
#{item_id}
</foreach>
</select>
foreach元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内是使用的集合项(item)和(index)变量。它允许你指定开头与结尾的字符串以及集合项迭代之间的分割符。这个元素也不会错误地添加多余的分隔符。
bind
bind元素允许你在OGNL表达式以外创建一个变量,并将其绑定到当前的上下文,如:
<!--public List<Employee> getEmpsTestInnerParameter(Employee employee); -->
<select id="getEmpsTestInnerParameter" resultType="com.atguigu.mybatis.bean.Employee">
<!-- bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值 -->
<bind name="_lastName" value="'%'+lastName+'%'"/>
<if test="_databaseId=='mysql'">
select * from tbl_employee
<if test="_parameter!=null">
where last_name like #{lastName}
</if>
</if>
<if test="_databaseId=='oracle'">
select * from employees
<if test="_parameter!=null">
where last_name like #{_parameter.lastName}
</if>
</if>
</select>
多数据库支持
如果配置了databaseIdProvider,你就可以在动态代码中使用名“_databased”的变量来为不同的数据库构建特定的语句。如下:
<databaseIdProvider type="DB_VENDOR">
<!-- 为不同的数据库厂商起别名 -->
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
<property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>
<!--public List<Employee> getEmpsTestInnerParameter(Employee employee); -->
<select id="getEmpsTestInnerParameter" resultType="com.atguigu.mybatis.bean.Employee">
<!-- bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值 -->
<bind name="_lastName" value="'%'+lastName+'%'"/>
<if test="_databaseId=='mysql'">
select * from tbl_employee
<if test="_parameter!=null">
where last_name like #{lastName}
</if>
</if>
<if test="_databaseId=='oracle'">
select * from employees
<if test="_parameter!=null">
where last_name like #{_parameter.lastName}
</if>
</if>
</select>
缓存机制
Mybatis包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。
Mybatis系统中默认定义了两级缓存。
一级缓存和二级缓存
- 默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启
- 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
- 为了提高扩展性。Mybatis定义了缓存接口Cache。我们可以通过是实现Cache接口来定义二级缓存。
一级缓存
本地缓存,作用域默认为SqlSession.当Session flush或close后,该Session中的所有Cache将被清空。
本地缓存不能被关闭,但可以调用clearCache()来清空本地缓存,或者改变缓存的作用域。
同一次会话期间只要查询过的数据都会保存在当前SqlSession的一个Map中
- key:hashCode + 查询色SqlId+编写的sql查询语句+参数
一级缓存失效的四种情况
- 不同的SqlSession对应不同的一级缓存
- 同一个SqlSession但是查询条件不同
- 同一个SqlSession两次查询期间执行了任何一次增删改操作
- 同一个SqlSession两次查询期间手动清空了缓存
二级缓存
二级缓存,全局作用缓存
二级缓存默认不开启,需要手动配置
Mybatis提供二级缓存的接口以及实现,缓存实现要求POJO是实现Serializable接口
二级缓存在SqlSession关闭或提交之后才会生效
使用步骤:
-
在全局配置文件中开启二级缓存
-
需要使用二级缓存的映射文件处使用cache配置缓存
-
注意:POJO需要实现Serializable接口
缓存相关属性
eviction=“FIFO”:缓存回收策略
- LRU-最近最少使用的:移除最长时间不被使用的对象
- FIFO-先进先出:按对象进入缓存的顺序来移除它们。
- SOFT-软引用:移除基于垃圾回收器状态和软引用规则的对象
- WEAK-弱引用:更积极地移除基于垃圾收集器和弱引用规则的对象。
- 默认是LRU。
缓存有关设置
-
全局setting的cacheEnable:
配置二级缓存的开关。一级缓存一直是打开的
-
select标签的useCache属性:
配置这个select是否使用二级缓存。一级缓存一直是使用的
-
sql标签的flushCache属性
增删改默认flushCache=true.sql执行以后,会同时清空一级和二级缓存。查询默认flushCache=false.
-
sqlSession.clearCache():
只是用来清除一级缓存
-
当在某一个作用域(一级缓存Session/二级缓存Namespace)进行了C/U/D操作后,默认该作用域下所有select中的缓存将被clear.
Mybatis-逆向工程(Generator生成器使用)IDEA
环境版本
Mysql-8.0
springboot-2.1.6
jdk-1.8
1.新建项目
2.在pom文件的<build>
下的<plugins>
添加以下配置
记住mysql连接一定添加在plugins中
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<configuration>
<!-- 在控制台打印执行日志 -->
<verbose>true</verbose>
<!-- 重复生成时会覆盖之前的文件-->
<overwrite>true</overwrite>
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
</configuration>
<!-- 数据库连接选择8.0以上的,因为用的mysql8.0-->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
</dependencies>
</plugin>
3.新建后面需要使用到的包
4.在mysql中建立测试数据库wg_inset
5.在resources下创建generatorConfig.xml
具体内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- context 是逆向工程的主要配置信息 -->
<!-- id:起个名字 -->
<!-- targetRuntime:设置生成的文件适用于那个 mybatis 版本 -->
<context id="default" targetRuntime="MyBatis3">
<!--optional,指在创建class时,对注释进行控制-->
<commentGenerator>
<property name="suppressDate" value="true"/>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--jdbc的数据库连接 wg_insert 为数据库名字-->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/wg_insert?useUnicode=true&characeterEncoding=utf-8&serverTimezone=UTC" userId="root"
password="123456"></jdbcConnection>
<!--非必须,类型处理器,在数据库类型和java类型之间的转换控制-->
<javaTypeResolver>
<!-- 默认情况下数据库中的 decimal,bigInt 在 Java 对应是 sql 下的 BigDecimal 类 -->
<!-- 不是 double 和 long 类型 -->
<!-- 使用常用的基本类型代替 sql 包下的引用类型 -->
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- targetPackage:生成的实体类所在的包 -->
<!-- targetProject:生成的实体类所在的硬盘位置 -->
<javaModelGenerator targetPackage="com.wglvzyx.mybatisredis.entity"
targetProject="src/main/java">
<!-- 是否允许子包 -->
<property name="enableSubPackages" value="false"/>
<!-- 是否对modal添加构造函数 -->
<property name="constructorBased" value="true"/>
<!-- 是否清理从数据库中查询出的字符串左右两边的空白字符 -->
<property name="trimStrings" value="true"/>
<!-- 建立modal对象是否不可改变 即生成的modal对象不会有setter方法,只有构造方法 -->
<property name="immutable" value="false"/>
</javaModelGenerator>
<!-- targetPackage 和 targetProject:生成的 mapper 文件的包和位置 -->
<sqlMapGenerator targetPackage="mapper"
targetProject="src/main/resources">
<!-- 针对数据库的一个配置,是否把 schema 作为字包名 -->
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!-- targetPackage 和 targetProject:生成的 interface 文件的包和位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.wglvzyx.mybatisredis.dao" targetProject="src/main/java">
<!-- 针对 oracle 数据库的一个配置,是否把 schema 作为字包名 -->
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!-- tableName是数据库中的表名,domainObjectName是生成的JAVA模型名,后面的参数不用改,要生成更多的表就在下面继续加table标签 -->
<table tableName="student" domainObjectName="Student"
enableCountByExample="false" enableUpdateByExample="false"
enableDeleteByExample="false" enableSelectByExample="false"
selectByExampleQueryId="false"></table>
<!-- tableName是数据库中的表名,domainObjectName是生成的JAVA模型名,后面的参数不用改,要生成更多的表就在下面继续加table标签 -->
<table tableName="post" domainObjectName="Post"
enableCountByExample="false" enableUpdateByExample="false"
enableDeleteByExample="false" enableSelectByExample="false"
selectByExampleQueryId="false"></table>
</context>
</generatorConfiguration>
6.跑起来看是否成功
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.562 s
[INFO] Finished at: 2019-07-29T11:55:44+08:00
[INFO] Final Memory: 17M/187M
[INFO] ------------------------------------------------------------------------
Process finished with exit code 0
控制台出现这个。表示成功了
查看生成的文件
Mybatis运行原理
SqlMapConfig.xml
,此文件作为MyBatis的全局配置文件,配置了mybatis的运行环境等信息。Mapper.xml文件即SQL映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。- 通过MyBatis环境等配置信息构造
SqlSessionFactory
即会话工厂 - 由会话工厂创建
SqlSession
即会话,操作数据库需要通过SqlSession进行。 - Mybatis底层自定义了Executor执行器接口操作数据库,
Executor
接口有两个实现,一个是基本执行器、一个是缓存执行器。 Mapped Statement
也是MyBatis一个底层封装对象,它包装了MyBatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。- Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对PreparedStatement设置参数。
- Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、Pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至Java对象中,输出结果映射过程相当于Jdbc编程中对结果的解析处理过程
1、根据配置文件创建SQLSessionFactory
2、返回SqlSession的实现类DefaultSqlSession对象。他里面包含了Executor和Configuration;Executor会在这一步被创建
3、getMapper返回接口的代理对象包含了SqlSession对象
4、查询流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tkKOUMVL-1644221812317)(C:\Users\QJS\AppData\Roaming\Typora\typora-user-images\image-20220121142901726.png)]
Mybatis-插件开发
1 PageHelper作用
官网:https://pagehelper.github.io/
PageHelper
是一个Mybatis的分页插件, 负责将已经写好的sql语句, 进行分页加工。官网说法:如果你也在用 MyBatis,建议尝试该分页插件,这一定是最方便使用的分页插件。分页插件支持任何复杂的单表、多表分页。
优点:无需你自己去封装以及关心sql分页等问题,使用很方便,前端取数据也很方便。
2 导入PageHelper插入依赖
<!--MyBatis的PageHelper插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.0.3</version>
</dependency>
3 添加分页插件配置
3.1SqlMapConfig.xml配置
如果是单独的Mybatis框架,需要在SqlMapConfig.xml添加分页插件的配置
<!--
plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下:
properties?, settings?,
typeAliases?, typeHandlers?,
objectFactory?,objectWrapperFactory?,
plugins?,
environments?, databaseIdProvider?, mappers?
-->
<plugins>
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!--数据库方言-->
<property name="helperDialect" value="mysql"/>
<!--合理化分页-->
<property name="reasonable" value="true"/>
</plugin>
</plugins>
必须注意配置的顺序,顺序出错,会执行报错!
3.2applicationContext.xml
如果是Mybatis与Spring整合,需要修改Spring的applicationContext.xml
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注意:这里还有其他Spring相关配置 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<value>
helperDialect=mysql
reasonable=true
</value>
</property>
</bean>
</array>
</property>
</bean>
4 编写Dao方法
package com.yiidian.dao;
import com.yiidian.domain.Customer;
import java.util.List;
/**
* Dao接口
*/
public interface CustomerDao {
/**
* 查询所有用户
*/
public List<Customer> findAll();
}
5、编写测试类
package com.yiidian.mybatis;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.yiidian.dao.CustomerDao;
import com.yiidian.domain.Customer;
import com.yiidian.utils.MyBatisUtils;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* MyBatis测试类 - PageHelper分页插件的使用
*/
public class TestCustomerDao {
@Test
public void test1(){
//1.获取SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSession();
//2.生成Dao代理对象
CustomerDao customerDao = sqlSession.getMapper(CustomerDao.class);
//3.设置分页参数
int pageNun = 1; // 页码
int pageSize = 2;// 每页显示条数
PageHelper.startPage(pageNun,pageSize);
//4. 查询用户数据
List<Customer> list = customerDao.findAll();
//5.把用户数据封装到PageInfo分页结果对象
PageInfo<Customer> page = new PageInfo<>(list);
//6.取出PageInfo的属性
//测试PageInfo全部属性
//PageInfo包含了非常全面的分页属性
System.out.println("当前页码="+page.getPageNum());
System.out.println("每页显示条数="+page.getPageSize());
System.out.println("当前页起始行号="+page.getStartRow());
System.out.println("当前页结束行号="+page.getEndRow());
System.out.println("总记录数="+page.getTotal());
System.out.println("总页数="+page.getPages());
System.out.println("是否为第1页="+page.isIsFirstPage());
System.out.println("是否为最后1页="+page.isIsLastPage());
System.out.println("是否有上一页="+page.isHasPreviousPage());
System.out.println("是否有下一页="+page.isHasNextPage());
System.out.println("当前页数据=");
for(Customer c:page.getList()){
System.out.println(c);
}
//7.关闭连接
sqlSession.close();
}
}
6、测试结果
PageHelper把所有分页结果数据封装到PageInfo对象,下面是打印出常用的属性
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
-
MyBatis测试类 - PageHelper分页插件的使用
*/
public class TestCustomerDao {
@Test
public void test1(){
//1.获取SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSession();//2.生成Dao代理对象 CustomerDao customerDao = sqlSession.getMapper(CustomerDao.class); //3.设置分页参数 int pageNun = 1; // 页码 int pageSize = 2;// 每页显示条数 PageHelper.startPage(pageNun,pageSize); //4. 查询用户数据 List<Customer> list = customerDao.findAll(); //5.把用户数据封装到PageInfo分页结果对象 PageInfo<Customer> page = new PageInfo<>(list); //6.取出PageInfo的属性 //测试PageInfo全部属性 //PageInfo包含了非常全面的分页属性 System.out.println("当前页码="+page.getPageNum()); System.out.println("每页显示条数="+page.getPageSize()); System.out.println("当前页起始行号="+page.getStartRow()); System.out.println("当前页结束行号="+page.getEndRow()); System.out.println("总记录数="+page.getTotal()); System.out.println("总页数="+page.getPages()); System.out.println("是否为第1页="+page.isIsFirstPage()); System.out.println("是否为最后1页="+page.isIsLastPage()); System.out.println("是否有上一页="+page.isHasPreviousPage()); System.out.println("是否有下一页="+page.isHasNextPage()); System.out.println("当前页数据="); for(Customer c:page.getList()){ System.out.println(c); } //7.关闭连接 sqlSession.close();
}
}
### 6、测试结果
PageHelper把所有分页结果数据封装到PageInfo对象,下面是打印出常用的属性
[[外链图片转存中...(img-PIIaQsIL-1644221812318)]](https://imgtu.com/i/7R9BuQ)