ORM
对象关系映射,这是一种思想.
JDBC开发步骤
1)加载数据库的驱动
2)通过DirverManager获取数据库链接
3)通过Connection获取Statement/PreparedStatement
4)将SQL语句绑定到上述对象,准备向数据库发起操作语句
5)执行完sql语句后,返回对象的结果
6)处理查询到的结果
7)依次关闭ResultSet Statement Connection
如果是非查询操作,记住开启事物支持
conn.setAutoCommit(false);
conn.commit()//conn.rollback()
Hibernate开发步骤
1)加载Configuration对象
2)加载实体映射文件
3)通过Configuration对象获取重量级SessionFactory对象
4)通过SessionFactory对象获取轻量级的session对象
5)通过session对象创建trsaction对象
6)执行操作
7)事物提交
8)关闭sesion
MyBatis
这是一个基于JAVA的持久层框架,前身是IBatis。
MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。
MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs映射成数据库中的记录。
工作流程
1)通过Reader对象读取src目录下的mybatis.xml配置文件
Reader reader = Resources.getResourceAsReader("mybatis.xml");
2)通过SqlSessionFactoryBuilder对象创建SqlSessionFactory对象
SqlSessionFactory sf = new SqlSessionFactorybuilder().build(reader);
3)从当前线程中获取SqlSession对象
SqlSession session = threadLocal.get();
if(session == null){
session = sf.openSession();
threadLocal.set(session);
}
4)开启事物(无需操作,自动开启)
5)通过SqlSession对象读取映射文件中的操作编号,从而读取sql语句
session.insert("userNameSpace.add");
6)事物提交
session.commit();
7)关闭session,分离SqlSession与当前线程的绑定
SqlSession session = threadLocal.get();
if(session != null){
session.close();
threadLocal.remove();
}
mybatis细节:
(1)在映射文件中书写的update delete insert标签只是一个模板可通用,但是select标签不能与其他的混用
(2)当实体属性名和数据库字段名完全一致时,<resultMap>映射关系可以省略不写,不一致时,必须明确声明
(3)当实体属性名和数据库字段名不一致时,返回值类型不能在使用resultType改用resultMap,其值为声明<resultMap>时的id值
(4)在mybatis的sql中,
#{id}表示占位符,其中的id表示参数名,如果输入的参数是简单类型,id可以是任意值
${value}表示拼接符,将接收到的参数的内容不加修饰的拼到sql中,此操作会引发sql注入问题,当输入的参数为简单类型时,{}中的值只能写为value
(5)在SQL中,对于主键自增的数据来说,在执行插入语句之后,可以立即通过select LAST_INSERT_ID()获取新增数据的id
所以在mybatis的insert中,可以利用这一点,再插入语句后,将生成的主键id设回pojo
<insert parameterType="pojo.User">
keyProperty将查询到主键的值设置到parameterType指定的pojo的对应属性中
<selectKey keyProperty="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(username,sex)value(#{username},#{sex})
</insert>
对于非自增的主键使用uuid或者序列
<selectKey keyProperty="id" resultType="string" order="BEFORE">
SELECT uuid()
</selectKey>
mybatis主配置文件:
properties:加载外部文件
文件读取优先级:外部文件 < 标签内属性 < paramType传递过来的属性
setting:全局参数配置
mybatis框架可以在运行时调整运行参数
typeAliases:别名定义
主要是将映射文件中的输出、输入中的pojo类型参数配在此处,有两种方式:
<typeAliases>
<typeAlias type="" alias=""/>单个别名:指定对应的类或接口对应的别名
<package name=""/>批量别名:mybatis会自动扫描包下的类或接口,将其类名声明为别名
</typeAliases>
typeHandlers:类型处理器
mybatis利用typeHandlers完成java类型和jdbc类型之间的转换
mappers:映射关系加载器,三种方式
<mappers>
<mapper resource="*Mapper.xml" />指定要加载xml文件
<mapper class="*Mapper"/>前提是遵循mapper接口的开发方式,并将xml文件和类文件名称统一,置于同一个目录中
<mapper package="*Mapper"/>如果想批量加载,只需要写出Mapper类的顶层包名即可
<mapper>
输入输出映射
输入输出映射时,可以使用基本类型,hashmap,pojo类
resultType VS resultMap
resultType只有当数据库字段名和实体属性名一一对应时,才能映射成功
当数据库字段名和实体属性名不对应时,使用resultMap定义输出
如果返回结果只有一行一列,可以使用简单类型接收
动态SQL
(1)where
select id,name,sal from students
<where>
<if test="name != null"> and name = #{name}</if>
<if test="sal != null"> and sal = #{sal}</if>
</where>
(2)set
update students
<set>
<if test="name != null"> name = #{name},</if>
<if test="sal != null"> sal = #{sal},</if>
</set>
(3)foreach
delete from students where id in
<foreach collection="array" open="(" close=")" separator="," item="ids">
#{ids}
</foreach>
(4)sql片段和 trim
<sql id="key">
<trim suffixOverrides=",">
<if test="id!=null">
id,
</if>
<if test="name!=null">
name,
</if>
<if test="sal!=null">
sal,
</if>
</trim>
</sql>
<sql id="value">
<trim suffixOverrides=",">
<if test="id!=null">
#{id},
</if>
<if test="name!=null">
#{name},
</if>
<if test="sal!=null">
#{sal},
</if>
</trim>
</sql>
<insert id="dynaSQLwithInsert" parameterType="cn.itcast.javaee.mybatis.app14.Student">
insert into students(<include refid="key"/>) values(<include refid="value"/>)
</insert>
关系映射
在mybatis中不像hibernate那样有明确的一对多,多对多关系,而是靠自己书写sql语句来完成的,
这时如果需要在一个resultMap中引入另一个resultMap(两个对象存在关系)使用
<association property="card" resultMap="cardNameSpace.cardMap" />
延迟加载
使用resultMap可以完成高级映射,这里借助了association和colleaction,这两个就具备延迟加载的能力
<association property="card" resultMap="cardNameSpace.cardMap" select="" column="">
select表示被管理查询的statementId,column表示两个表之间的关联字段名
mybatis延迟加载默认是关闭的,需要在setting中开启
lazyLoadingEnabled设为true
aggressiveLazyLoading设为false
查询缓存
mybatis提供了查询缓存来减轻数据库的压力,分为一级缓存和二级缓存
一级缓存:sqlSession级别缓存,在数据库构造sqlSession对象时,就在对象中准备了一个hashMap结构来存储缓存数据,系统默认开启
二级缓存:mapper级别缓存,多个sqlSession去操作同一个Mapper的sql语句,多个sqlSession共享二级缓存中的数据
每个mapper都有一个二级缓存,而这个区别是根据namespace来的,也就是说,如果两个mapper的namespace一样,则两个mapper公用一个二级缓存
二级缓存默认是关闭的,要开启需要在setting中和mapper中都要开启,并且将实体实现序列化接口
如果对数据库有写操作(更新 删除 新增),当立即执行sqlSession.commit()操作来更新缓存
mybatis的重要API
sqlSessionFactory:
重量级接口,单例模式
sqlSession:
线程不安全的,最佳应用场合是方法体内
mybatis开发方式:
(1)原始dao开发方式
问题:存在大量的模板方法
调用sqlSession方法时,将statement的id硬编码了
调用sqlsession方法时传入的变量,由于sqlSession方法使用Object接收参数,无法在编译时校验输入的参数是否有类型错误
(2)mapper代理开发方式
在使用mapper代理开发时,需要遵循一些开发规范
(1)*Mapper.xml中的namespace为mapper接口的全路径一致
(2)接口方法的方法名要与xml中的statement的id一致
(3)接口方法的参数值要与xml中的parameterType指定的类型一致
(3)接口方法的返回值要与xml中的resultType指定的类型一致
这样就可以自动生成代理类StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);