Mybatis3学习日记。

来源:互联网 发布:网络被高智慧生物屏蔽 编辑:程序博客网 时间:2024/06/11 05:26
Mybatis学习
Mybatis和hibernate同属于ORM框架,其中两者最显著的区别就在于hibernate是全自动框架,不是开发人员手写sql语句,但配置相对繁琐。Mybatis则是半自动化ORM框架,与数据库交互的语句都需要自己来写。
Mybatis使用的核心是SqlsessionFactory对象的实例,而SqlsessionFactory对象的实例可以通过SqlsessionFactoryBuilder对象来获得,SqlsessionFactoryBuilder可以通过配置XML来获取,有点晕了,直接看代码吧。

从XML中构建SqlsessionFactory
下面这个xml的配置信息是Mybatis的基础配置信息,包括对数据库的连接信息和实体类对应的mapper.xml的映射。
<span style="font-size:14px;"><?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://Mybatis.org/dtd/mybatis-3-config.dtd"><configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mysql"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><mappers><mapper resource="org/mybatis/example/BlogMapper.xml"/></mappers></configuration></span>
接下来就使用Java代码来获取SqlSessionFactory对象实例并执行接口中定义的查询方法
<span style="font-size:14px;">package org.mybatis.test;import java.io.IOException;import java.io.Reader;import java.util.List;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.mybatis.example.Blog;import org.mybatis.example.BlogMapper;public class MybatisTest {public static void main(String[] args) throws IOException {SqlSessionFactory sqlMapper = null;String resource = "classpath:Configuration.xml";Reader reader = Resources.getResourceAsReader(resource);sqlMapper = new SqlSessionFactoryBuilder().build(reader);SqlSession session = sqlMapper.openSession();BlogMapper blogMapper = session.getMapper(BlogMapper.class);List<Blog> list = blogMapper.selectAll();}}</span>
如上所示,最终取得的SqlSession中包含了数据库的连接信息和实体类对应的xml文件映射,这样就可以直接使用接口来进行方法的调用了。

接下来说一下Mybatis的xml配置文件属性信息,先看一下配置文件的高层结构有哪些。
configuration配置
  •  properties属性
  •  settings设置
  •  typeAliases类型命名
  •  typeHandlers类型处理器
  •  objectFactory对象工厂
  •  plugins插件
  •  environments环境
  •  environment环境变量
  •  transactionManager事务管理器
  •  dataSource数据源
  •  映射器
properties属性可以对配置进行赋值,格式为<property name  = "" value=""/>

settings是对Mybatis运行的机制进行设置的,全部的属性设置有这些:
<span style="font-size:14px;"><settings><setting name="cacheEnabled" value="true"/>--是全局映射器启用或禁用缓存<setting name="lazyLoadingEnabled" value="true"/>--全局启用或禁用延迟加载<setting name="multipleResultSetsEnabled" value="true"/>--允许或不允许多种结果集从一个单独的语句中返回<setting name="useColumnLabel" value="true"/>--使用列标签代替列名<setting name="useGeneratedKeys" value="false"/>--允许JDBC支持生成的键<setting name="enhancementEnabled" value="false"/>--全局性地启用或禁用运行时字节码增强<setting name="defaultExecutorType" value="SIMPLE"/>--配置默认的执行器。SIMPLE执行器没有什么特别之处。REUSE执行器重用预处理语句。BATCH执行器重用语句和批量更新<setting name="defaultStatementTimeout" value="25000"/>--设置超时时间</settings></span>

typeAlias:是为Java类型命名一个短的名字,而不至于每次使用java类型都需要带上包名,下面看个示例
<typeAliases><typeAlias alias="Blog" type="domain.blog.Blog"/></typeAliases>
这样配置的好处是,在使用到Blog类的地方,只需要书写上Blog就可以,而不用书写完整的类名。

environments是用来配置多种环境的,在配置多种环境的时候,SqlSessionFactory只能选择一个。

transactionManager是Mybatis对事务的管理,管理器类型有2种,
1.JDBC - 这个配置直接简单使用了JDBC的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围。
2.MANGED - 这个配置几乎没做什么。它从来不提交或回滚一个连接。而它会让容器来管理事务的整个生命周期。

dataSource是对数据库资源配置的属性,数据源类型分为3种
1.UNPOOLED这个数据源的实现是每次被请求时简单打开和关闭连接,只能配置一下5种属性值,driver、url、username、password、defaultTransactionIsolationLevel(默认的连接事务隔离级别)
2.POOLED这是JDBC连接对象的数据源连接池的实现,用来避免创建新的连接实例时必要的初始连接和认证时间,除了上述的那5种属性外还可以配置以下属性,
  •  poolMaximumActiveConnections – 在任意时间存在的活动(也就是正在使用)连接的数量。默认值:10
  •  poolMaximumIdleConnections – 任意时间存在的空闲连接数。
  •  poolMaximumCheckoutTime – 在被强制返回之前,池中连接被检查的时间。默认值:20000毫秒(也就是20秒)
  •  poolTimeToWait – 这是给连接池一个打印日志状态机会的低层次设置,还有重新尝试获得连接,这些情况下往往需要很长时间(为了避免连接池没有配置时静默失败)。默认值:20000毫秒(也就是20秒)
  •  poolPingQuery – 发送到数据的侦测查询,用来验证连接是否正常工作,并且准备接受请求。默认是“NO PING QUERY SET”,这会引起许多数据库驱动连接由一个错误信息而导致失败。
  •  poolPingEnabled – 这是开启或禁用侦测查询。如果开启,你必须用一个合法的SQL语句(最好是很快速的)设置poolPingQuery属性。默认值:false。
  •  poolPingConnectionsNotUsedFor – 这是用来配置poolPingQuery多次时间被用一次。这可以被设置匹配标准的数据库连接超时时间,来避免不必要的侦测。默认值:0(也就是所有连接每一时刻都被侦测-但仅仅当poolPingEnabled为true时适用)。
mappers是对sql语句映射的设置,大多使用相对于类路径的资源来确认sql映射文件的位置。以下是映射文件的顶级元素
1. cache - 配置给定命名空间的缓存
2. cache - ref 从其他命名空间引用缓存配置
3. resultMap 描述从数据库取出数据来加载对象
4. sql 可以重用的sql块,可以被其他语句引用
以及insert select delete update这4种对数据库的常用操作命令。

select元素是最常用的数据库查询语句,元素有很多属性可以配置,以下详细描述
<span style="font-size:14px;"><select id=”selectPerson” parameterType=”int” parameterMap=”deprecated” resultType=”hashmap”resultMap=”personResultMap”flushCache=”false”useCache=”true”timeout=”10000”fetchSize=”256”statementType=”PREPARED”resultSetType=”FORWARD_ONLY”></span>
  1. id:命名空间唯一的标识符
  2. parameterType:sql语句用到的参数类型
  3. resultType:sql语句返回的结果类型,不能与resultMap同时使用
  4. resultMap:可以对多个表信息的返回进行定制
  5. flushCache:无论什么语句被执行,都会对缓存进行清空
  6. useCache:将本条语句的结果缓存
  7. timeOut:连接数据库的超时时间限制
  8. fetchSize:每次批量返回的行数,默认不设置
  9. statementType:STATEMENT,PREPARED,CALLABLE,相当于从statement、preparedStatement、CallableStatement中选择一个
  10. resultSetTYpe:默认不设置
insert语句相较于select的属性,多了一个useGeneratedKeys,设置true表示主键自增。当不支持主键自增时,可以使用下面这种方式来手动给主键赋值
<insert id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" keyProperty=""useGeneratedKeys="true" timeout="20000">
还有1个KeyPorperty,这个属性用来标记一个属性,只对insert有效,默认不设置,在下面的随机定义主键id时会使用。

随机ID生成方法
<insert id="insertAuthor" parameterType="domain.blog.Author"><selectKey keyProperty="id" resultType="int" order="BEFORE">select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1</selectKey>insert into Author(id, username, password, email,bio, favourite_section)values(#{id}, #{username}, #{password}, #{email}, #{bio},#{favouriteSection,jdbcType=VARCHAR})</insert>
KeyProperty:selectKey语句结果应该被设置为目标属性
resultType:结果类型
order:可以被设置为BEFORE或者AFTER,区别在于是否先对主键进行赋值
statementType:同上

Sql这个元素可以被用来定义重用的代码段,可以被包含在其他的语句中,如下所示
<sql id=”userColumns”> id,username,password </sql><select id=”selectUsers” parameterType=”int” resultType=”hashmap”>select <include refid=”userColumns”/>from some_table where id = #{id}</select>
可以对所有sql语句中的公共部分进行设置,以减少代码的书写和保证字段的正确性。

resultMap是mybatis中最重要的元素,相较于resultType的单一指定数据类型或者javaBean类,resultMap可以自由组合多表数据列。下面看一下最简单的应用,先定义一个resultMap,字段信息有3个
<resultMap id="userResultMap" type="User"><id property="id" column="user_id" /><result property="username" column="user_name"/><result property="password" column="hashed_password"/></resultMap>
然后在查询语句中进行引用
<select id=”selectUsers” parameterType=”int”resultMap=”userResultMap”>select user_id, user_name, hashed_password from some_table where id = #{id}</select>
这是对resultMap最简单的应用,返回字段为User类的字段信息,在select属性中进行引用。如果要求返回类型为多表字段的组合该怎么办?
<select id="selectBlogDetails" parameterType="int"resultMap="detailedBlogResultMap">select B.id as blog_id,B.title as blog_title,B.author_id as blog_author_id,A.id as author_id,A.username as author_username,A.password as author_password,A.email as author_email,A.bio as author_bio,A.favourite_section as author_favourite_section,P.id as post_id,P.blog_id as post_blog_id,P.author_id as post_author_id,P.created_on as post_created_on,P.section as post_section,P.subject as post_subject,P.draft as draft,P.body as post_body,C.id as comment_id,C.post_id as comment_post_id,C.name as comment_name,C.comment as comment_text,T.id as tag_id,T.name as tag_name from Blog Bleft outer join Author A on B.author_id = A.id left outer join Post P on B.id = P.blog_idleft outer join Comment C on P.id = C.post_id left outer join Post_Tag PT on PT.post_id = P.idleft outer join Tag T on PT.tag_id = T.id where B.id = #{id}</select>
这是一个多表查询的select语句,对于这样的多表查询,返回结果类型该怎么定义?
<resultMap id="detailedBlogResultMap" type="Blog"><constructor><idArg column="blog_id" javaType="int"/></constructor><result property="title" column="blog_title"/><association property="author" column="blog_author_id" javaType=" Author"><id property="id" column="author_id"/><result property="username" column="author_username"/><result property="password" column="author_password"/><result property="email" column="author_email"/><result property="bio" column="author_bio"/><result property="favouriteSection" column="author_favourite_section"/></association><collection property="posts" ofType="Post"><id property="id" column="post_id"/><result property="subject" column="post_subject"/><association property="author" column="post_author_id" javaType="Author"/><collection property="comments" column="post_id" ofType=" Comment"><id property="id" column="comment_id"/></collection><collection property="tags" column="post_id" ofType=" Tag" ><id property="id" column="tag_id"/></collection><discriminator javaType="int" column="draft"><case value="1" resultType="DraftPost"/></discriminator></collection></resultMap>
这个resultMap是对上面的多表联接查询的结果集设置,其中的属性非常多,一个一个来说。

constructor:用来向实体类中的构造方法进行值的设置,属性有2个,分别为
idArg:ID参数
arg:注入到构造方法的一个普通结果
<constructor><idArg column="id" javaType="int"/><arg column=”username” javaType=”String”/></constructor>

association:用来处理“有一个”类型的关系,“有一个”表示当前查询表与外键表的关系为“一对一”或者“多对一”的关系,关联映射就映射在这种结果上。
<association property="author" column="blog_author_id" javaType=" Author"><id property="id" column="author_id"/><result property="username" column="author_username"/></association>
常用的属性有:
property:映射到列的结果或者属性
column:数据库的列名,如果存在复合主键,可以使用column="{prop1=col1,prop2=col2}"这种语法来传递语句
javaType:java类名或者其他集合类型
JDBCType:支持的JDBC类型列表中的类型
typeHandler:默认的类型处理器
select:关联嵌套查询所使用的属性,如果有联合主键,使用方法同column

mybatis有2种关联方式,分别为
嵌套查询:通过执行另外一个SQL映射语句来返回预期的复杂类型
嵌套结果:通过嵌套结果映射来处理重复的联合结果的子集

嵌套查询:
<mapper namespace="org.mybatis.example.BlogMapper"><resultMap type="Blog" id="blogResultMap"><id property="id" column="id"/><result property="name" column="name"/><association property="author" column="author_id"javaType="Author" select="selectAuthor"/></resultMap><sql id="qjbl">name,pwd</sql><select id="selectAll" parameterType="int" resultMap="blogResultMap">select * from blog where id = #{id}</select><select id="selectAuthor" parameterType="int" resultType="Author">select * from author where id = #{id}</select></mapper>
这就是嵌套查询的关联方式,在关联设置里使用其他定义好的<select>来进行关联数据,但是这种方式有一个弊端,如果关联的数据返回的数据不是一条,而是成百上千条的话,select所需要执行的次数就会有成百上千次,也就是所谓的N+1,这是非常不明智的举动,所以就有了嵌套结果关联的方式来解决这种返回条数过多的结果集。

嵌套结果:
<resultMap type="Blog" id="blogResultMap"><id property="id" column="id"/><result property="name" column="name"/><association property="author" column="author_id"javaType="Author" resultMap="authorResultMap"/></resultMap><resultMap type="Author" id="authorResultMap"><id property="id" column="id"/><result property="nickname" column="nickname"/></resultMap><sql id="qjbl">name,pwd</sql><select id="selectAll" parameterType="int" resultMap="blogResultMap">select a.id,a.nickname,b.id,b.name,b.pwd,b.author_id from blog b,author a where a.id = b.author_id and b.id = #{id}</select>
这种嵌套结果的好处是所引用的resultMap可以重复使用,嵌套结果相较于嵌套查询,在描述上更为清晰,且不会存在N+1的问题。如果不需要这种引用方式的resultMap,也可以写成下面这种嵌套形式的。
<resultMap type="Blog" id="blogResultMap"><id property="id" column="id"/><result property="name" column="name"/><association property="author" column="author_id" javaType="Author"><id property="id" column="id"/><result property="nickname" column="nickname"/></association></resultMap>
“有一个”的2种关联查询方式都说完了,那么“有多个”该怎么查询呢?

collection:集合的作用和用法与上面说的关联几乎是相同的,那么不同点在上面地方呢。那就是关联是针对“有一个”,而结果映射为多个的时候,就要用到collection了。
嵌套查询:
<resultMap type="Blog" id="blogResultMap"><id property="id" column="id"/><result property="name" column="name"/><collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPosts"/></resultMap><select id="selectAll" parameterType="int" resultMap="blogResultMap">select b.id,b.name,b.pwd,b.author_id  from blog b where b.id = #{id}</select><select id="selectPosts" parameterType="int" resultType="Post">select * from post where blog_id = #{id}</select>
用法与关联几乎一模一样,但是有2个地方需要我们来关注,一个就是javaType属性变成了ArrayList,因为结果映射是多条数据,所以使用集合来存储。第二个地方就是多了一个OfType属性,这个属性是用来区分javabean的属性类型。ps:在很多时候javaType属性是不需要的,mybatis可以自己算出来,所以可以省略不写。




















0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 摩拜单车手机号码换了怎么办 摩拜单车换手机号码打不开怎么办 摩拜单车丢了怎么办 摩拜单车忘锁了怎么办 透明手机壳粘指纹怎么办 tpu手机壳变黄了怎么办 0pp0手机声音小怎么办 橡胶皮套晒坏了怎么办 宝宝晚上吹空调发烧怎么办 玩手机手指尖疼怎么办 手机型号不支持微信运动怎么办 手腕向下压会疼怎么办 手腕韧带拉伤怎么办恢复快 华为手机用车载充电慢怎么办 华为麦芒6充电慢怎么办 oppo手机压弯了怎么办 麦芒5电池不耐用怎么办 华为7x照相模糊怎么办 华为麦芒6照相虚怎么办 荣耀8gps信号弱怎么办 华为麦芒4手机卡顿怎么办 华为麦芒4玩游戏卡怎么办 sim卡换卡通讯录丢了怎么办 换sim卡通讯录怎么办 麦芒4开不了机怎么办 麦芒5开不了机怎么办 麦芒6针丢了怎么办 麦芒6扬声器坏了怎么办 华为手机2s太卡怎么办 华为麦芒6网速慢怎么办 华为麦芒5太卡怎么办 小米note3拍照反应慢怎么办 华为刷机后还要账号密码怎么办 刷机后忘记华为账号和密码怎么办 荣耀7x耗电快怎么办 小米2s死机后怎么办? 电信合约卡不想用了怎么办 vivo合约机掉了怎么办 华为合约机丢了怎么办 两年合约机掉了怎么办 电信合约机丢了怎么办