近两天对mybatis的使用进行了简单的回顾。接下来我把我这两天所学的东西做一些简单的总结。
Mybatis是基于ORM的一款优秀的持久型层框架。作为现行两大流行的开源持久性之一,它能帮助程序员减少大量的重复工作。使其工作的方式也是有两种基于XML或基于注解。本次学习主要以XML的形式进行,使用的开发工具为IDEA UI,MAVEN。
创建学习项目结构如下:
安装:
在pom.xml文件中添加mybatis,及数据库相关依赖:
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version> 3.1.1</version> </dependency> <!-- https://mvnrepository.com/artifact/cglib/cglib
用于提供mybatis的二级缓存
--> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.2</version> </dependency> <!--junit4--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!—配置mysqldatabase--> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.39</version> </dependency> <!—配置数据库数据库连接池--> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.18</version> </dependency> <!--database end-->
创建实体类:
public class Emp { private int empId; private String empName; private Date hireDate; private Dept dept; private Dept coDept; getter & seter 方法
。。。。。 }
public classDept implementsSerializable{
private int deptNo;
private StringdeptName;
getter & setter方法
}
Mybatis依赖的配置文件有两类,xxxMapper.xml和mybatis.xml。前者作为实体类的操作类在mybatis中的注册形式,后者为mybatis的Configureation,xxxMapper.xml要想真正起作用就必须要在mybatis.xml文件中进行注册。
我们先聊聊mybatis.xml,mybatis.xml作为mybatis的配置文件,承担着为其设置全局属性,管理实体类的操作类的重要作用。头文件格式如下:
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPEconfigurationPUBLIC"-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
常见元素有以下几类:
<configuration>:配置,配置文件的最顶层元素,对应Congfigureation类。
< properties>:
提供通用配置,通过它提供的属性值可用在对数据库相关信息的配置等。通过它配置的信息也可以通过外部的properties文件提供,还可以通过方法参数传递。Configureation在加载配置时先在<properties>下的<property>中查找,其次查找配置文件的属性。
<settings>:
对mybatis配置的全局设置,其相关信息将直接影响到mybatis的运行行为。可用setting如下
<settings>
<!--映射器中配置的缓存的全局开关,value:true|false-->
<settingname="cacheEnabled"value="true"/>
<!--lazyloadingEnabled,延迟加载的全局开关,开启设置为true
则在运行时所有关联对象都将延迟加载,当关联对象通过fetchType设置过加载方式
后,该设置将不起作用-->
<settingname="lazyLoadingEnabled"value="true"/>
<!--当开启时,所有方法将在运行时将加载拥有该方法的对象的所有属性,
3.1.4版本以上默认开启 ?-->
<settingname="aggressiveLazyLoading"value="false"/>
<!--是否允许单一语句返回多结果集-->
<settingname="multipleResultSetsEnabled"value="true"/>
<!--使用列标签代替列名,默认值为true-->
<settingname="useColumnLabel"value="true"/>
<!--允许 JDBC支持自动生成主键,需要驱动兼容,默认为false-->
<settingname="useGeneratedKeys"value="true"/>
<!--指定 MyBatis应如何自动映射列到字段或属性。
value={ NONE 表示取消自动映射;
PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集;
FULL 会自动映射任意复杂的结果集(无论是否嵌套)}
作用与resultMap的autoMapping功能相同,
在嵌套映射中通常会同时配置上columnPrefix属性,
这样的话可以在一定程度上避免因为实体属性名
相同导致mybatis无法正确赋值的问题
-->
<settingname="autoMappingBehavior"value="PARTIAL"/>
<!--指定发现自动映射目标未知列(或者未知属性类型)的行为。
NONE: 不做任何反应
WARNING: 输出提醒日志
('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARN)
FAILING: 映射失败 (抛出SqlSessionException)-->
<!--<settingname="autoMappingUnknownColumnBehavior"value="WARNING"/>-->
<!--配置默认的执行器。
SIMPLE 就是普通的执行器;REUSE执行器会重用预处理语句(prepared statements);
BATCH 执行器将重用语句并执行批量更新。
-->
<settingname="defaultExecutorType"value="SIMPLE"/>
<!--设置超时时间,它决定驱动等待数据库响应的秒数。非零正数-->
<settingname="defaultStatementTimeout"value="25"/>
<!--为驱动的结果集获取数量(fetchSize)设置一个提示值。
此参数只可以在查询设置中被覆盖。-->
<!--<settingname="defaultFetchSize" value="100"/>-->
<settingname="safeRowBoundsEnabled"value="false"/>
<!--保证自动映射-->
<settingname="mapUnderscoreToCamelCase"value="TRUE"/>
<settingname="localCacheScope"value="SESSION"/>
<settingname="jdbcTypeForNull"value="OTHER"/>
<!--指定哪个对象的方法触发一次延迟加载,
值为用”,“分割开来的方法名列表-->
<settingname="lazyLoadTriggerMethods"value="equals,clone,hashCode,toString"/>
</settings>
<typeAliases> :
为项目中自定义的类起别名,有利于后面代码编写过程中减少工作量。
其实类别名不单可以为类设置别名,也可以指定为一个包名。在指定包名后mybatis可以自己在指定包名下加载需要的类。
如:
<typeAliastype="com.midea.mybatisexample.vo.Emp"alias="Emp"/>
<packagename="com.midea.mybatisexample.util"></package>
<typeHandlers>:类处理器
用于指定JDBC数据类型与java类型之间的对应关系。如果没有想要的匹配关系我们也可以自己重写类型处理器或创建你自己的类型处理器具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口。
<plugins>
mybatis允许在映射语句的执行过程中拦截某些方法的调用:
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
自定义插件的方式:
实现Interceptor,指定要拦截的方法————
@Intercepts({@Signature(
type= Executor.class,
method = "update",
args = {MappedStatement.class,Object.class})})
<environments>:配置环境
由于一个项目可能在开发过程和应用过程中使用多个数据库来进行开发。 MyBatis 可以配置成适应多种环境。尽管mybatis可以配置多个环境,但一个SqlSessionFactory只能对应一个environmenet。一个environment标签可以有一个<dataSource>子标签和一个<trancationsManger>子标签。
<dataSource>指定当前环境所配置的数据的数据源。mybatis默认提供[UNPOOLED|POOLED|JNDI]三种类型的数据源,用户也可以自定义数据源。
如:
<dataSourcetype="com.midea.mybatisexample.util.DruidDataSourceFactory"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="url" value="${db.url}"/> <property name="username" value="${db.username}"/> <property name="password" value="${db.password}"/> </dataSource>
DruidDataSourceFactory是我自己使用druid数据库连接池配置的数据源:
public classDruidDataSourceFactory extendsUnpooledDataSourceFactory{
public DruidDataSourceFactory(){
//dataSource
this.dataSource= newDruidDataSource();
}
}
由上面的类可见配置方法并不复杂,只需继承org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory类并将数据源指向自己提供的数据库连接类即可。
<mappers>:映射器
告诉Mybatis查找需要执行的映射文件所在的位置
四种方式:
resource | 使用相对路径的方式加载 |
url | 使用全路径 |
class | 使用注解的方式时注册Mapper功能时使用, 指向mapper类 |
package | 使用注解的方式时注册Mapper功能时使用, 指向mapper类所在包 |
Mapper文件:以EmpMapper为例:
头文件:
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPEmapper
PUBLIC"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
推荐的mapper结构
<!--cache – 给定命名空间的缓存配置。
cache-ref – 其他命名空间缓存配置的引用。
resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
parameterMap – 已废弃!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除。
sql – 可被其他语句引用的可重用语句块。
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句
-->
<!—namespace对应Dao的全类名 -->
<mappernamespace="com.midea.mybatisexample.dao.EmpDao">
<!— -useGeneratedKeys使用数据库的自增字段,要使用该属性应该确保在对应数据库表的对应字段已设置了自增字段
id应与对应Dao的对应方法名一致
— ->
<insertid="addEmp"parameterType="list"useGeneratedKeys="true"keyProperty="empId">
insert into t_emp(empNAme,deptNo,co_dept,hireDate)VALUES
<!- -foreach 用于批量插入数据 collection 为数据在java中存储的方式可选值有list,array- ->
<foreachcollection="list"item="emp"separator=",">
(#{emp.empName},#{emp.dept.deptNo},#{emp.coDept.deptNo},#{emp.hireDate,javaType=date,jdbcType=DATE})
</foreach>
</insert>
<!--一对一关系的几种表示方法-->
<!---各个元素的基本属性(property,Column)必须完全-->
<resultMapid="empMap"type="Emp">
<idproperty="empId"column="empId"/>
<resultproperty="empName"column="empName"/>
<resultproperty="hireDate"column="hireDate"/>
<!--association 用于处理have a类型的依赖关系-->
<associationproperty="dept"column="deptNo"javaType="Dept">
<idproperty="deptNo"column="deptNo"/>
<resultproperty="deptName"column="DeptName"/>
</association>
</resultMap>
<selectid="getEmp1" resultMap="empMap">
select e.*,d.DeptName from t_emp e left outerjoin t_dept d on e.deptNo= d.DEPTNO
</select>
<resultMapid="empMap3"type="Emp">
<idproperty="empId"column="empId"/>
<resultproperty="empName"column="empName"/>
<resultproperty="hireDate"column="hireDate"/>
<!--association 用于处理have a类型的依赖关系,使用reslutMap属性调用一个外部resultMap
特点是可以增加代码的重用性。
-->
<associationproperty="dept"column="deptNo"javaType="Dept"resultMap="deptMap"/>
<!--使用select属性调用另一个sql语句完成查询,
缺点容易造成1+N问题
-->
<associationproperty="coDept"column="co_dept"javaType="Dept"select="getDept"
/>
</resultMap>
<resultMapid="deptMap"type="Dept">
<idproperty="deptNo"column="deptNo"/>
<resultproperty="deptName"column="DeptName"/>
</resultMap>
<selectid="getEmp3" resultMap="empMap3">
select e.*,d.DeptNamefrom t_emp e
left outer join t_dept d on e.deptNo= d.DEPTNO
WHERE e.empId =#{empId}
</select>
<selectid="getDept"resultType="Dept">
select * from t_deptwhere t_dept.DEPTNO=#{id}
</select>
<!--if-->
<selectid="getEmpByEmpName"resultType="int">
<!--模糊查询-->
select count(*)from t_emp where contact((contact(‘%’,#{value}),’%’)
</select>
< - -清空表 - ->
<deleteid="clearEmp">
DELETE From t_emp
</delete>
</mapper>