Java框架之MyBatis 06-全局配置-mapper映射-分步查询
MyBatis
MyBatis是Apache的一个开源项目iBatis, iBatis一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。 iBatis 提供的持久层框架包括SQL Maps和Data Access Objects(DAO)
Mybatis 是一个 半自动的ORM(Object Relation Mapping)框架
sql和java编码分开,功能边界清晰,一个专注业务、一个专注数据
MyBatis全局配置
MyBatis全局配置文件结构顺序是规定好的,可以省略但不可颠倒位置
1)properties属性
既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来配置
还可以创建一个资源文件,通过properties引入外部文件
resource: 从类路径下引入属性文件
url: 引入网络路径或者是磁盘路径下的属性文件
<properties> <property name="driver" value="com.mysql.jdbc.Driver" /> </properties> <!-- 引入类路径下文件 --> <properties resource="db.properties"></properties>
是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为
<settings> <!-- 映射下划线到驼峰命名 --> <setting name="mapUnderscoreToCamelCase" value="true"/> <!-- 设置Mybatis对null值的默认处理 --> <setting name="jdbcTypeForNull" value="NULL"/> <!-- 开启延迟加载 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 设置加载的数据是按需还是全部 --> <setting name="aggressiveLazyLoading" value="false"/> <!-- 配置开启二级缓存 --> <setting name="cacheEnabled" value="true"/> </settings>
3)typeAliases 别名处理
类型别名是为 Java 类型设置一个短的名字,可以方便我们在配置文件中其他位置引用某个类。
很多的情况下,可以批量设置别名为这个包下的每一个类创建一个默认的别名,就是用简单类名小写的形式
<typeAliases> <package name="com.mybatis.bean"/> </typeAliases>
MyBatis已经取好的别名
4)typeHandlers 类型处理器
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型
MyBatis3.4以前的版本需要我们手动注册这些处理器,以后的版本都是自动注册的,所以基本不需设置
我们也可以重写类型处理器或创建自己的类型处理器来处理不支持的或非标准的类型
- 实现org.apache.ibatis.type.TypeHandler接口或者继承org.apache.ibatis.type.BaseTypeHandler
- 指定其映射某个JDBC类型(可选操作)
- 在mybatis全局配置文件中注册
5)objectFactory 对象工厂
6)plugins 插件机制
我们可以通过插件来修改MyBatis的一些核心行为。插件通过动态代理机制,可以介入四大对象的任何一个方法的执行
<plugins> <!-- 分页插件 --> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
四大对象
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) ParameterHandler (getParameterObject, setParameters) ResultSetHandler (handleResultSets, handleOutputParameters) StatementHandler (prepare, parameterize, batch, update, query)
7)environments 环境配置
MyBatis可以配置多种环境,根据需要每种环境使用一个environment标签进行配置并指定唯一标识符
可以通过environments标签中的default属性指定一个环境的标识符来快速的切换环境
id:指定当前环境的唯一标识 transactionManager、和 dataSource 都必须有
<environments default="mysql"> <environment id="mysql"> <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>
实际开发中我们使用Spring管理数据源,并进行事务控制的配置来覆盖上述配置
8)databaseIdProvider数据库厂商标识
MyBatis 可以根据不同的数据库厂商执行不同的语句
<databaseIdProvider type="DB_VENDOR"> <property name="MySQL" value="mysql"/> </databaseIdProvider>
Type: DB_VENDOR, 使用MyBatis提供的VendorDatabaseIdProvider解析数据库厂商标识。也可以实现DatabaseIdProvider接口来自定义.
配置了databaseIdProvider后,在SQL映射文件中的增删改查标签中使用databaseId来指定数据库标识的别名
<select id="getEmployeeById" resultType="com.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 的相同语句,则后者会被舍弃。
9)mappers 映射器
用来在mybatis初始化的时候,告诉mybatis需要引入哪些Mapper映射文件
resource : 引入类路径下的文件
url : 引入网络路径或者是磁盘路径下的文件
class : 引入Mapper接口
通常情况下使用批量注册,这种方式要求SQL映射文件名必须和接口名相同并且在同一目录下
<mappers> <package name="com.mybatis.dao"/> </mappers>
mapper 映射文件
MyBatis 的真正强大在于它的映射语句,就是针对 SQL 语句构建的
<mapper namespace="main.mapper.BookMapper" > </mapper>
SQL 映射文件有很少的几个顶级元素
cache – 给定命名空间的缓存配置。
cache-ref – 其他命名空间缓存配置的引用。
resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
parameterMap – 已废弃!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除,这里不会记录。
sql – 可被其他语句引用的可重用语句块。
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语
MyBatis 默认不是自动提交,需手动提交:sqlSession.commit();
insert
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> INSERT INTO users (id,username,PASSWORD) VALUES(NULL,#{username},#{password}) </insert>
delete
<delete id="deleteUser"> DELETE FROM users WHERE id = #{id} </delete>
update
<update id="updateUser"> UPDATE users SET name=#{name},email=#{email} WHERE id = #{id} </update>
select
<select id="getUserById" resultType="main.beans.User"> SELECT id,username,`password`,`name`,email FROM users WHERE id = #{id} </select>
主键生成与获取
数据库分为支持主键自增与不支持的,mysql是支持的
功能:插入一条新数据时,即可通过其主键id值立马查询这条数据,一般在 insert 中设置 useGeneratedKeys 为 true,返回数据库自动生成的主键 id,keyColumn 用于指定数据库table中的主键,keyProperty 用于指定传入对象的成员变量。
注意:settings 中设置为全局,在接口映射器(注解)中设置的 useGeneratedKeys 参数值将会覆盖在settings元素中设置全局 useGeneratedKeys 参数值,xml 映射器中配置的 useGeneratedKeys参数只会对 xml 映射器产生影响
@Options(useGeneratedKeys=true,keyProperty="userId",keyColumn="userId")
参数传递
1) 单个普通类型参数
可以接受基本类型,包装类型,字符串类型等。这种情况MyBatis可直接使用这个参数,#{abc},大括号内可随便定义
2) 多个参数
任意多个参数,都会被MyBatis重新包装成一个Map传入。Map的key是param1,param2,或者0,1…, #{param1,param2}
值就是参数的值 #{key1,key2}:获取参数的值,预编译到SQL中。安全。
3) 命名参数
为参数使用@Param起一个名字,MyBatis就会将这些参数封装进map中,key就是我们自己指定的名字
public Employee getEmployeeById(@Param("id")Integer id);
4) POJO
resultType自动映射,当这些参数属于我们业务POJO时,我们直接传递POJO
autoMappingBehavior默认是PARTIAL,开启自动映射的功能。唯一的要求是结果集列名和javaBean属性名一致
5) Map
我们也可以封装多个参数为map,直接传递 #{key} 直接传入map中的key值
1) 查询单行数据返回Map集合
public Map<String,Object> getEmployeeByIdReturnMap(Integer id );
2) 查询多行数据返回Map集合
@MapKey("id") // 指定使用对象的哪个属性来充当map的key public Map<Integer,Employee> getAllEmpsReturnMap();
6) Collection/Array
会被MyBatis封装成一个 map 传入, Collection 对应的 key 是 collection , Array 对应的 key 是 array . 如果确定是 List 集合,key 还可以是 list.
resultMap自定义映射
自定义 resultMap,可以实现高级结果集的映射
1) id :用于完成主键值的映射
2) result :用于完成普通列的映射
id、result属性
<resultMap id="getBookById" type="main.beans.User"> <id column="id" property="id"></id> <result column="username" property="username"></result> <result column="password" property="password"></result> </resultMap>
3) association :一个复杂的类型关联,当一个对象的某个属性是一个对象时,一般将结果包装成此类型
我们可以使用联合查询,并以级联属性的方式封装对象.使用 association 标签定义对象的封装规则
<select id="getEmployeeAndDept" resultMap="myEmpAndDept" > SELECT e.id eid, e.last_name, e.email,e.gender ,d.id did, d.dept_name FROM tbl_employee e , tbl_dept d WHERE e.d_id = d.id AND e.id = #{id} </select> <resultMap type="com.mybatis.beans.Employee" id="myEmpAndDept"> <id column="eid" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> <!-- 级联的方式 --> <result column="did" property="dept.id"/> <result column="dept_name" property="dept.departmentName"/> </resultMap>
对于每个实体类都应该有具体的增删改查方法,也就是DAO层,因此我们也可以使用 association 分步查询
在分步查询的基础上,可以使用延迟加载来提升查询的效率,只需要在全局的 Settings 中配置
<select id="getEmployeeAndDeptStep" resultMap="myEmpAndDeptStep"> select id, last_name, email,gender,d_id from tbl_employee where id =#{id} </select> <resultMap type="com.mybatis.beans.Employee" id="myEmpAndDeptStep"> <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.mybatis.dao.DepartmentMapper.getDeptById" //mapper包中定义的查询方法全类名 column="d_id" fetchType="eager"> </association> </resultMap>
4) collection :复杂类型的集,当一个对象的某个属性是一个集合对象时
我们可以使用联合查询,并以级联属性的方式封装对象.使用 collection 标签定义对象的封装规则
property: 关联的属性名
ofType: 集合中元素的类型
实际的开发中经常可以通过分步的方式完成查询.
<select id="getDeptAndEmpsByIdStep" resultMap="myDeptAndEmpsStep"> select id ,dept_name from tbl_dept where id = #{id} </select> <resultMap type="com.mybatis.beans.Department" id="myDeptAndEmpsStep"> <id column="id" property="id"/> <result column="dept_name" property="departmentName"/> <collection property="emps" select="com.mybatis.dao.EmployeeMapper.getEmpsByDid" //mapper包中定义的查询方法全类名 column="id"> </collection> </resultMap>
分步查询多列值的传递
如果分步查询时,需要传递给调用的查询中多个参数,则需要将多个参数封装成 Map来进行传递,语法如下: {k1=v1, k2=v2….}
在所调用的查询方法取值时,就要参考Map的取值方式,需要严格的按照封装map 时所用的key来取值.
fetchType属性
在<association> 和 <collection> 标签中都可以设置 fetchType,指定本次查询是否要使用延迟加载。默认为 fetchType=”lazy” ,如果本次的查询不想使用延迟加载,则可设置为 fetchType=”eager”.