使用MyBatis时主要是完成POJO和SQL的映射规则
MyBatis基本构成:
SqlSessionFactoryBuilder
SqlSessionFactory
SqlSession
SqlMapper(主要是定义参数类型,描述缓存,描述SQL语句,定义查询结果和POJO的映射关系)
配置(<configuration>):
<properties/>
在<properties>中可以定义参数如数据库密码,用户名等形式如:
<properties> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/test" /> <property name="username" value="root" /> <property name="password" value="root" /> </properties>
然后以${name}方式可以引用
此外可以直接引入properties文件,如:
<properties resource="jdbc.properties"/>
<settings/>用于开户mybatis的一些功能,常用的主要有如下:
<settings> <!-- 该配置影响的所有映射器中配置的缓存的全局开关。默认值true --> <setting name="cacheEnabled" value="true"/> <!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。默认值false --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 将积极加载改为消息加载即按需加载 --> <setting name="aggressiveLazyLoading" value="false"/> </settings>
<typeAlases/>用法如下,另外注意的是MyBatis提供了很多的类型别名,一般直接使用的是封装类,如int其实是Integer,基本类型是_int:
<!-- 设置别名 --> <typeAliases> <!-- type指的是javabean的完全限定名 alias就是指代别名--> <typeAlias alias="student" type="cn.entity.Student" /> </typeAliases>
<typeHandlers/>
<objectFactory/>
<plugins/>
<environments>
<enviroment>
<transactionManager/>
<dataSource/>
<environment>
</environments>
environments的使用:
<environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <!-- 配置数据库连接信息 --> <dataSource type="POOLED"> <!-- value属性值引用db.properties配置文件中配置的值 --> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${name}" /> <property name="password" value="${password}" /> </dataSource> </environment> </environments>
映射器:
元素:select insert update delete sql resultMap cache
<?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.m24.demo.dao.AppointmentMapper"> <cache /> <resultMap id="appointment" type="com.m24.demo.entity.Appointment"> <id property="bookId" column="book_id"/> <id property="studentId" column="student_id"/> <result property="appointTime" column="appoint_time"/> <association property="book" column="book_id" select="com.m24.demo.dao.BookMapper.queryById" /> <association property="student" column="student_id" select="com.m24.demo.dao.StudentMapper.queryById" /> </resultMap> <insert id="insertAppointment"> INSERT INTO appointment (book_id, student_id) VALUES (#{bookId}, #{studentId}) </insert> <select id="queryWithStudentId" resultMap="appointment" useCache="true"> SELECT a.book_id, a.student_id, a.appoint_time FROM appointment a INNER JOIN student b ON a.student_id = b.student_id WHERE a.student_id = #{studentId} </select> </mapper>
主键回填(userGeneratedKey, keyProperty):
<insert id="insertBook" parameterType="com.m24.demo.entity.Book" useGeneratedKeys="true" keyProperty="bookId"> INSERT ignore INTO book(book_name,book_number ) VALUES (#{bookName},#{bookNumber}) </insert>
关联查询:
<collection property="book" column="book_id" select="com.m24.demo.dao.BookMapper.queryById" /> <association property="student" column="student_id" select="com.m24.demo.dao.StudentMapper.queryById" />
参数传递时,可使用以下2种方法:
1、参数自动映射,或配置POJO(列名和属性名不同时)
2、使用注解@Param
public interface AppointmentMapper { /** * * @param bookId * @param studentId * @return */ int insertAppointment(@Param("bookId")long bookId,@Param("studentId")long studentId); /** * * @param bookId * @return */ Appointment queryWithStudentId(@Param("studentId")long studentId); }
缓存 <cache/>,使用缓存时,POJO必须是可序列化的,默认下
<cache eviction:="LRU" flushInterval="100000" size="1024" readOnly="true"/>
select缓存,insert update delete 刷新缓存
自定义缓存,实现org.apache.ibatis.cache.Cache接口,然后在<cache type="??"/>中指定type,
CRUD中,可使用flushCache,useCache配置SQL层面的缓存规则
注意:缓存和延迟加载不是同一个东西
动态SQL:
if:test测试
<if test="var != null and var != '' ""> ... </if>
choose(when, otherwise):
<choose> <when test="???"> ... </when> <otherwise> ... </otherwise> </choose>
trim(where, set):
<trim prefix="语句前缀" suffixOverrides="要去掉的字串"> ... </trim>
foreach:
<foreach item="sex" index="index" collection="sexList" open="(" seperator=";" close=")"> #{sex} </foreach>
MyBatis解析运行原理:
1、读取配置文件缓存到Configuration对象,创建SqlSessionFactory
2、执行SqlSession
MyBatis中普遍使用反射技术:
反射: JDK动态代理: 1、编写服务类和接口,这个是真正的服务提供者,在JDK代理中接口是必须的 2、编写代理类(InvocationHandler),提供绑定(Proxy.newProxyInstance)及代理方法invoke CGLIB动态代理: 1、编写代理类MethodInterceptor,实现回调方法intercept 2、指定父类enhancer.setSupperClass,设置回调方法enhancer.setCallback,动态创建子类enhancer.create
有关反射详细:http://www.cnblogs.com/m2492565210/p/7250628.html
SqlSession四大对象:
Executor:执行器,由它调度StatementHandler(使用数据库Statement,PreparedStatement执行操作), ParameterHandler(参数处理), ResultHandler(数据集封装返回处理)
插件:
开发插件时,要实现Interceptor接口,实现里面的intercept plugin setProperties方法,然后在plugins注册
使用例子 1.写一个类,并且实现Interceptor接口 2.在上述类使用@Intercepts注解,配置拦截信息 3.在配置文件配置插件 @Intercepts({ @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }) }) public class MyInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { // TODO Auto-generated method stub } } 配置文件加入 <plugins> <plugin interceptor="weber.mybatis.plugin.MyInterceptor" /> </plugins>
Spring-MyBatis:
事务控制的2个点:隔离级别和传播行为
隔离级别:
脏读 | 不可重复读 | 幻读 | |
读未提交 | Y | Y | Y |
读写提交 | N | Y | Y |
可重复读 | N | N | Y |
序列化 | N | N | N |
传播行为:
REQUIRED:业务方法需要在一个容器里运行。如果方法运行时,已经处在一个事务中,那么加入到这个事务,否则自己新建一个新的事务。
NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行。
REQUIRESNEW:不管是否存在事务,该方法总汇为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建。
MANDATORY:该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出异常。
SUPPORTS:该方法在某个事务范围内被调用,则方法成为该事务的一部分。如果方法在该事务范围外被调用,该方法就在没有事务的环境下执行。
NEVER:该方法绝对不能在事务范围内执行。如果在就抛异常。只有该方法没有关联到任何事务,才正常执行。
NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。
MyBatis默认使用Log4j记录日志,使用时应在classpath中配置log4j.properties文件
MyBatis使用原始Dao和Mapper接口两种方法实现Dao,实现Dao时应该要注意SqlSession是线程不安全的,每个线程都应该有自己的实例,每个Session都应控制在一个请求或一个方法内,并在每次使用后要关闭Session(finally)
使用原始Dao开发方式,需要编写Dao接口和对应的实现类及映射文件,Dao实现类通过SqlSession及sql.xml文件中的sql id完成数据库读写
Mapper接口需要编写mapper接口和mapper文件,开发规范:
mapper.xml文件中的namespace和mapper接口类路径相同
mapper接口方法名和mapper.xml中定义的statement的id相同
mapper接口输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
mapper接口输出参数类型和mapper.xml中定义的每个sql的resutType的类型相同