个人读书笔记,题外话都写在第1章https://blog.csdn.net/u013652550/article/details/119800308。
? ? ? ? 第6章主要带我们学习了MyBatis相关知识,对ORM框架有了初步认识。本章关于配置的项目内容过于繁琐,很难记忆,用时查询即可。
6.1 ORM框架介绍
? ? ? ? ORM(Object Relation Mapping,对象关系映射)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。
MyBatis的使用
? ? ? ??引入对应依赖即可,书本给的version是3.4.6,实测无效,自动填充为2.0.6。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
? ? ? ? MyBatis包含一个名叫Resources的工具类,包含一些实用方法,可方便地加载资源。这里使用Reader加载。亦可使用InputStream、Configuration等。调用openSession()、selectList、selectOne等方法使用。(可传入Object参数,如示例中的2,类似于PreparedStatement中的setter方法)
String resource = "mybatis-config.xml";
Reader reader = Resources.getResourceAsReader(resource);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
String statement = "UserMapper.getUserList";
List<User> users = session.selectList(statement);
User u = session.selectOne(statement, 2);
6.2 XML配置
mybatis-config.xml
? ? ? ? 主配置文件,顶层元素<configuration>,需要注意配置元素顺序匹配(可空)。[properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins? environments?, databaseIdProvider?, mappers?]
?????????以下列举一下书上提到的元素:
properties属性
? ? ? ? 可使用resource进行外部引用,并进行补充。后续配置中可用${...}引用。注意覆盖优先级:通过方法参数传递的属性具有最高优先级,resource/url属性中指定的配置文件次之,最低优先级的是properties属性中指定的属性。
<properties resource="database.properties">
<property name="..." value="..."/>
</properties>
?settings
????????配置项过多,建议直接跳过,使用默认配置。详见书P95~97。使用<settings>内嵌套<setting name="..." value="..."/>配置。有效值留白为布尔类型(true|false)。
settings各项的意图、默认值
设置参数 | 描述 | 有效值 | 默认值 |
---|
cacheEnabled | 全局缓存 | | true | lazyLoadingEnabled | 全局延迟加载 | | false | aggressiveLazyLoading | 非按需加载 | | false | multipleResultSetsEnabled | 允许单一语句多返回集 | | true | useColumnLabel | 使用列标签代替列名 | | true | useGeneratedKeys | 允许JDBC支持自动生成主键 | | false | autoMappingBehavior | 如何自动映射 | NONE, PARTIAL, FULL | PARTIAL | autoMappingUnknownColumnBehavior | 未知列映射 | NONE, WARNING, FAILING | NONE | defaultExecutorType | 默认执行器 | SIMPLE, REUSE, BATCH | SIMPLE | defaultStatementTimeout | 超时时间 | 正整数 | null | defaultFetchSize | 结果集数量提示值 | 正整数 | null | safeRowBoundsEnabled | 允许嵌套语句中分页 | | false | safeResultHandlerEnabled | 允许嵌套语句中分页 | | true | mapUnderscoreToCamelCase | 自动开启驼峰命名规则映射 | | false | localCacheScope | 加速重复嵌套 | SESSION, STATEMENT | SESSION | jdbcTypeForNull | 空值类型 | JdbcType常量 | OTHER | lazyLoadTriggerMethods | 设置触发延迟加载的方法名 | CSV(逗号分隔值) | equals, clone, hashCode, toString | defaultScriptingLanguage | 动态SQL默认语言 | 类型别名或完全限定类名 | org.apache.ibatis.scripting. xmltags.XMLLanguageDriver | defaultEnumTypeHandler | 指定Enum使用的默认TypeHandler | 类型别名或完全限定类名 | org.apache.ibatis.type. EnumTypeHandler | callSettersOnNulls | 结果集中值为nul时是否调用setter方法 | | false | returnInstanceForEmptyRow | 返回空行而不是null | | false | logPrefix | 日志前缀 | String | null | proxyFactory | 延迟加载对象代理 | CGLIB, JAVASSIST | JAVASSIST | vfsImpl | VFS(虚拟文件系统)实现 | CSV,全限定类名 | null | useActualParamName | 使用方法签名中的名称作为语句参数名称 | | true | configurationFactory | 指定提供Configuration实例的类 | 类型别名或全类名 | null |
typeAliases
? ? ? ? 设置别名。或在指定包名下搜索,在没有注解@Alias的情况下,使用Bean的非限定类名来作为它的别名。
<typeAliases>
<typeAlias type="com..." alias="xxx"/>
<package name="com..."/>
</typeAliases>
typeHandlers
? ? ? ? 默认类型处理器:见书P99~100。注意enum使用EnumTypeHandler存储name值,使用EnumOrdinalTypeHandler存储序号值。学习enum类型的使用:
public enum UserState {
DISABLED(0),
AVAILABLE(1);
private final int status;
UserState(int status) {
this.status = status;
}
public int getStatus() {
return status;
}
}
? ? ? ? 示例代码中:注意更新数据库(update, insert)后要调用session.commit()。
????????自定义处理器:实现BaseTypeHandler<T>接口中的4个方法即可。
public class CusEnumStatusHandler extends BaseTypeHandler<UserState> {
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, UserState userState, JdbcType jdbcType) throws SQLException {
preparedStatement.setInt(i, userState.getStatus());
}
@Override
public UserState getNullableResult(ResultSet resultSet, String s) throws SQLException {
return UserState.fromValue(resultSet.getInt(s));
}
@Override
public UserState getNullableResult(ResultSet resultSet, int i) throws SQLException {
return UserState.fromValue(resultSet.getInt(i));
}
@Override
public UserState getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return UserState.fromValue(callableStatement.getInt(i));
}
}
配置环境environments
? ? ? ? 在项目开发过程中往往有几套环境,如开发、测试和生产环境。配置environments元素时只需加上default指定默认环境,每个环境都用environment元素嵌套在其中配置。此外,之前加载SqlSessionFactory时其实省略了第二、三个参数,即environment和properties。
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
? ? ? ? 配置environment元素时指定id。然后依次配置:
? ? ? ? 事务管理器transactionManager:type可以为JDBC或MANAGED,区别在于后者让容器管理事务。如果需要,设置closeConnection为false阻止默认关闭连接。如果使用Spring就没有必要配置事务管理器,Spring模块会使用自带的管理器来覆盖前面的配置。
<transactionManager type="JDBC">
<property name="closeConnection" value="false"/>
</transactionManager>
? ? ? ? 数据源dataSource:type可以为UNPOOLED、POOLED、JNDI。详见书P106。 ? ? ? ? ? ? ? ? UNPOOLED:在每次请求时打开和关闭连接。包含driver、url、username、password、defaultTransactionIsolationLevel(默认事务隔离级别) 5个属性。 ? ? ? ? ? ? ? ? POOLED:利用“池”获得更快的速度。在UNPOOLED的基础上还有以下更多属性:poolMaximumActiveConnections(最大同时连接数)、poolMaximumIdleConnections(最大空闲连接数)、poolMaximumCheckoutTime(被检出最长时间,默认20000ms)、poolTimeToWait(最长等待时间,默认20000ms)、poolMaximumLocalBadConnectionTolerance(坏连接容忍度,默认3)、poolPingQuery(侦测查询)、poolPingEnabled(是否启用侦测查询)、poolPingConnectionsNotUsedFor(侦测查询频率,默认0)。 ? ? ? ? ? ? ? ? JNDI:为了能在EJB等容器中使用,放置一个JNDI上下文的引用即可。属性有两个:initial_context、data_source。
映射器mappers
? ? ? ? 一般在同级目录下新建mapper文件夹存储映射配置文件。
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
6.3 XML映射文件
? ? ? ? 以下列举可配置属性列表,通过单词含义基本能见名知意。
1. 查询元素select
? ? ? ? id、parameterType、resultType、resultMap、flushCache、useCache、timeout、fetchSize(设置批量返回行数)、statementType(STATEMENT、PREPARED、CALLABLE,默认为PREPARED)、resultSetType(FORWARD_ONLY、SCROLL_SENSITIVE、SCROLL_INSENSITIVE,默认null)、databaseId(配置databaseIdProvider后生效)、resultOrdered(嵌套结果集而不是引用,默认false)、resultSets(CSV,给多结果集分别命名)。
2. 更新元素insert、update、delete
? ? ? ? id、parameterType、flushCache、timeout、statementType、useGeneratedKeys(默认false)、keyProperty(标记属性,设置返回主键值,默认null,可以为CSV)、keyColumn(通过生成键值设置列名,可以为CSV)、databaseId。
<insert id="addUser" parameterType="user">
<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
SELECT LAST_INSERT_ID()
</selectKey>
insert into t_user (name, age, money, status) values (#{name}, #{age}, #{money}, #{status, typeHandler=org.apache.ibatis.type.EnumTypeHandler})
</insert>
? ? ? ? selectKey元素属性:id、parameterType、resultType、resultMap、flushCache、useCache。
3. 可重用语句块sql
? ? ? ? 为sql语句块设置id后即可使用include包含。属性值可以用在include元素的refid属性里或include内部语句中。可以在语句中使用${...},使用include时用property设置。贴一下书本示例:
<sql id="userColumns">
${alias}.id, ${alias}.name, ${alias}.age, ${alias}.money, ${alias}.status
</sql>
<sql id="sometable">
${prefix}user as ${alias}
</sql>
<sql id="someinclude">
from
<include refid="${include_target}"/>
</sql>
<select id="getUserList2" resultMap="userResult">
select
<include refid="userColumns">
<property name="alias" value="t1"/>
</include>
<include refid="someinclude">
<property name="prefix" value="t_"/>
<property name="alias" value="t1"/>
<property name="include_target" value="sometable"/>
</include>
</select>
4. 数据集映射resultMap
? ? ? ? constructor:包含idArg、arg。构造方法注入。 ? ? ? ? id:结果ID。 ? ? ? ? result:普通结果。常用column、property。属性注入。 ? ? ? ? association:关联类型。常用property、javaType(类型名)。使用resultMap直接引用已有映射集。 ? ? ? ? collection:关联类型集合。常用property、javaType(类型名)、ofType(集合类型)。使用resultMap直接引用已有映射集。 ? ? ? ? discriminator:根据结果值决定使用哪个resultMap。类似于switch-case语法。
5. 缓存和自定义缓存
? ? ? ? MyBatis默认开启一级缓存:同一个SqlSession,多次调用同一个Mapper和同一个方法的同一个参数,只会进行一次数据库查询。
? ? ? ? 默认不开启二级缓存。二级缓存可以在SqlSessionFactory层面给各个SqlSession对象共享。在配置中settings元素设置cacheEnabled参数为true,在映射文件中添加一行<cache/>即可。
<cache eviction="LRU" flushInterval="100000" size="1024" readOnly="true"/>
? ? ? ? eviction:缓存回收策略。LRU:最少使用原则;FIFO:先进先出原则;SOFT:软引用;WEAK:弱引用。 ? ? ? ? flushInterval:刷新时间间隔,单位ms。 ? ? ? ? size:引用额数目。 ? ? ? ? readOnly:设置为false时相同SQL后面访问的可能是cache的clone版本。
? ? ? ?在Mapper的具体方法下可以使用useCache、flushCache等设置对二级缓存的访问意愿。自定义缓存:实现org.apache.ibatis.cache.Cache接口。
public interface Cache {
String getId();
void putObject(Object key, Object value);
Object getObject(Object key);
Object removeObject(Object key);
void clear();
int getSize();
default ReadWriteLock getReadWriteLock() {
return null;
}
}
? ? ? ? 只有当调用了commit()方法,MyBatis才会往缓存中写入数据。
6.4 动态SQL
1. if语句
? ? ? ? 示例中使用了两种传参数的方式:一种是string,另一种是map。用map可以传多个参数。bind的使用中可以在sql中增加%%。参数中可以不带。
<select id="..." parameterType="string" resultMap="...">
select * from t_user where 1=1
<if test="_parameter!=null and _parameter!=''">
and name like #{_parameter}
</if>
</select>
<select id="..." parameterType="map" resultMap="...">
<bind name="pattern value="'%' + _parameter.name + '%'" />
select * from t_user where 1=1
<if test="_parameter.name!=null and _parameter.name!=''">
and name like #{pattern}
</if>
</select>
? ? ? ? 以上演示了bind的使用。调用示例:
List<User> users = session.selectList(statement, "%J%");
2. choose(when, otherwise)语句
? ? ? ? 类似于switch-case-default语句的使用。配置示例:
<choose>
<when test="type=='city'">
AND city like #{pattern}
</when>
<when ...>...</when>
<otherwise>...</otherwise>
</choose>
3. trim语句
? ? ? ? prefix:在trim标签内为sql语句加上前缀。 ? ? ? ? suffix:在trim标签内为sql语句加上后缀。 ? ? ? ? suffixOverrides:指定去除多余的后缀内容。 ? ? ? ? prefixOverrides:制定去除多余的前缀内容。
<trim prefix="set" suffixOverrides=",">
<if test="_parameter.cardNo!=null and _parameter.cardNo!=''">
cardNo = #{cardNo},
</if>
<if test="_parameter.city!=null and _parameter.city!=''">
city = #{city},
</if>
</trim>
<trim prefix="WHERE" prefixOverrides="and|or">
<if test="_parameter.id!=null and _parameter.id!=''">
and id = #{id}
</if>
<if test="_parameter.address!=null and _parameter.address!=''">
and address = #{address}
</if>
</trim>
4. foreach语句
? ? ? ? Item:每个元素迭代时的别名。 ? ? ? ? Index:每次迭代到的位置。 ? ? ? ? Open:以什么开始。 ? ? ? ? Separator:分隔符。 ? ? ? ? Close:以什么结束。
<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
? ? ? ? 调用示例:需要传递一个map参数。(复习自动拆包与解包)
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
Map<String, Object> map = new HashMap<>();
map.put("ids", ids);
List<User> users = session.selectList(statement, map);
6.5 逆向工程
? ? ? ? 引入依赖:mybatis-generator-core,引入插件:maven-compiler-plugin和mybatis-generator-maven-plugin。之前已贴过很多引入的XML配置代码,以后不再贴。加载maven变更。
? ? ? ? 书上对于逆向工程的使用仅仅贴了一段代码。关于逆向工程的使用这里有详细介绍:MyBatis逆向工程代码的生成以及使用详解(持续更新)_Oxygenzzz的博客-CSDN博客_mybatis逆向工程这里稍微剖析一下。顶层标签:generatorrConfiguration,然后是一项context,需设置id和targetRuntime("MyBatis3")。context包含如下元素:
commentGenerator
? ? ? ? 设置suppressDate和suppressAllComments属性,布尔型。示例中均为true。
jdbcConnection
? ? ? ? 设置数据库驱动,数据库地址及表名,账号,密码。driverClass、connectionURL、userId、password。
javaTypeResolver
? ? ? ? 配置自定义类型解析器。使用属性<property name="..." value="..."/>配置。
javaModelGenerator
? ? ? ? 生成Model类的包名及存放位置。示例:targetPackage="com..."、targetProject="src/main/java"。属性有两项,enableSubPackages、trimStrings,示例中均为true。
sqlMapGenerator
? ? ? ? 生成映射文件的包名及存放位置。元素同上一项,但属性中无trimStrings。
javaClientGenerator
? ? ? ? 生成DAO类的包名及存放位置。元素同上一项,增加了type(="XMLMAPPER")。
table
? ? ? ? 生成对应表及类名。tableName、domainObjectName(设置实体名)、enableCountByExample、enableUpdateByExample、enableDeleteByExample、enableSelectByExample、selectByExampleQueryId。后五项示例中均为false。
6.6 分页插件pagehelper
? ? ? ? 在pom.xml中引入pagehelper依赖。在mybatis-config.xml中配置拦截器。属性项dialet设置方言,rowBoundsWithCount默认为false,设置为true时使用RowBounds分页会进行count查询。
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialet" value="mysql"/>
<property name="rowBoundsWithCount" value="true"/>
</plugin>
</plugins>
? ? ? ? 调用示例代码如下:
PageHelper.startPage(1, 5, true);
PageInfo<Users> pageInfo = new PageInfo<User>(users);
int 数据总数 = pageInfo.getTotal();
int 数据总页数 = pageInfo.getPages();
int 最后一页 = pageInfo.getLastPage();
|