mybatis 与数据库交互,处理数据的dao层。
第一部分 配置文件
<configuration> 根标签
<properties ></properties>
<settings>
<!-- 具体的参数名和参数值 -->
<setting name="" value=""/>
</settings>
<!-- 类型名称:为一些类定义别名 -->
<typeAliases></typeAliases>
<!-- 类型处理器:定义Java类型与数据库中的数据类型之间的转换关系 -->
<typeHandlers></typeHandlers>
<!-- 对象工厂 -->
<objectFactory type=""></objectFactory>
<plugins>
<plugin interceptor=""></plugin>
</plugins>
<!-- 环境:配置mybatis的环境 -->
<environments default="">
<!-- 环境变量:可以配置多个环境变量,比如使用多数据源时,就需要配置多个环境变量 -->
<environment id="">
<!-- 事务管理器 -->
<transactionManager type=""></transactionManager>
<!-- 数据源 -->
<dataSource type=""></dataSource>
</environment>
</environments>
<!-- 数据库厂商标识 -->
<databaseIdProvider type=""></databaseIdProvider>
<!-- 映射器:指定映射文件或者映射类 -->
<mappers></mappers>
</configuration>
<properties resource="db.properties"></properties> 可以引入外部属性文件,使用${}括号获取属性值,也可以使用property子标签,定义属性值。
<settings>全局定义mybatis属性设置,类如开启懒加载,启用驼峰命名法等。
<typeAliases>
<typeAlias alias="user" type="com.data.entry.user"></typeAlias> 定义类的别名。
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</dataSource>
</environment>
</environments>
设置数据库环境,包括事务处器,以及数据源配置,default属性指定默认使用那个environment.
在 MyBatis 中有两种类型的事务管理器(也就是 type=”[JDBC|MANAGED]”)
JDBC – 这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域
MANAGED – 这个配置几乎没做什么,而是让容器来管理事务的整个生命周期, 默认情况下它会关闭连接。
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
阻止它默认的关闭行为
三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”) POOLED连接池
映射文件 <mapper resource="mapper.xml"></mapper> 类路径下
映射器类
<mapper class="com.data.mapper.ThreeMapper"></mapper> 使用注解器类,没有映射文件
<package name=""/>包下的所有都是映射器类
加载配置文件
String resouce="mybatis-config.xml"; 类路径下,如果有多层路径,使用/分割
InputStream inputStream= Resources.getResourceAsStream(resouce);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
sqlSession=sqlSessionFactory.openSession();
SqlSessionFactoryBuilder有5个方法,
SqlSessionFactory build(InputStream inputStream) 重载了三个,加载外部属性
SqlSessionFactory build(Configuration config) 不使用配置文件,记载configuration类
Resources 工具类,这个类在 org.apache.ibatis.io 包中。Resources 类正如其名,会帮助你从类路径下、文件系统或一个 web URL 中加载资源文件。
手动配置 configuration 实例
DataSource dataSource = BaseDataTest.createBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.setLazyLoadingEnabled(true);
configuration.setEnhancementEnabled(true);
configuration.getTypeAliasRegistry().registerAlias(Blog.class);
configuration.addMapper(BoundAuthorMapper.class);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(configuration);
SqlSessionFactory
SqlSessionFactory 有六个方法创建 SqlSession 实例。
考虑三点:事务处理:我需要在 session 使用事务或者使用自动提交功能(auto-commit)吗?(通常意味着很多数据库和/或 JDBC 驱动没有事务)
连接:我需要依赖 MyBatis 获得来自数据源的配置吗?还是使用自己提供的配置?
执行语句:我需要 MyBatis 复用预处理语句和/或批量更新语句(包括插入和删除)吗?
SqlSession openSession()
SqlSession openSession(boolean autoCommit)
SqlSession openSession(Connection connection)
SqlSession openSession(TransactionIsolationLevel level)
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level)
Configuration getConfiguration();
SqlSession执行语句的方法,事物的方法
<T> T selectOne(String statement, Object parameter)
sqlSession.getMapper(TwoMapper.class);加载映射器类
void commit()
void commit(boolean force)
void rollback()
void rollback(boolean force)
Mybatis 使用到了两种缓存:本地缓存(local cache)和二级缓存(second level cache)。
每当一个新 session 被创建,MyBatis 就会创建一个与之相关联的本地缓存。任何在 session 执行过的查询语句本身都会被保存在本地缓存中,那么,相同的查询语句和相同的参数所产生的更改就不会二度影响数据库了。本地缓存会被增删改、提交事务、关闭事务以及关闭 session 所清空。
默认情况下,本地缓存数据可在整个 session 的周期内使用,这一缓存需要被用来解决循环引用错误和加快重复嵌套查询的速度,所以它可以不被禁用掉,但是你可以设置 localCacheScope=STATEMENT 表示缓存仅在语句执行时有效。
void clearCache()清空本地缓存
void close()关闭
第二部分
映射
所有的映射器类,必须是接口,而且规定映射器类为xxxMapper
二*一 基于映射文件和XXMapper接口 处理数据库设置。
映射文件的根节点是mapper <mapper namespace="com.data.mapper.OneMapper">属性namespace要关联相应的接口类。
<insert id="addUser" useGeneratedKeys="true" keyProperty="id"> 属性id要和接口相应的方法相同
insert into users (name,password) values(#{user},#{password});
</insert>
void addUser(@Param("user") String user, @Param("password") Integer password);
useGeneratedKeys 指定主键自增
keyProperty 指定JavaBean属性对应数据库表中的主键
通过以上设置获取自增主键。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表
但仅对插入和删除语句有用。
<update id="changePassword">
update users set password=#{new} where password=#{old}
</update>
void changePassword(@Param("new") Integer new1, @Param("old")Integer old);
delete id="delUser">
delete from users where name=#{user} AND password=#{password}
</delete>
void delUser(@Param("user")String user,@Param("password")Integer password);
<select id="allUser" parameterType="int" resultType="user">
select * from users where id=#{id}
</select>
user allUser(@Param("id")int id);
resultType指定SQL结果返回类型,user类相应的属性要有setter方法和无参的构造函数。
parameterType指定参数类型
返回的结果封装成map,即一个类封装成一个map,键为类的属性名,值为属性对应的值。SQL语句返回的结果为一行记录
<select id="onemap" resultType="map">
select * from users where id=4
</select>
HashMap<String ,Object>onemap();
返回的结果封装成List,SQL语句返回的行数一条以上。
<select id="listuser" resultType="user">
select * from users
</select>
List<user> listuser(); resultType此时是List中元素的类型
返回的结果封装成map,
<select id="mapuser" resultType="user">
select * from users
</select>
@MapKey("id") 指定类中那个属性值为主键,也就是map的键
HashMap<Integer ,user> mapuser();
传入的参数是List,Array
<select id="listarg" parameterType="java.util.List" resultType="user">
select * from users where id in
<foreach collection="list" item="item" index="index" open="(" separator="," close=")">
#{item}
</foreach>
</select>
List<user> listarg(@Param("list") List<Integer> list);
collection指定集合类型,如List Array
item本次迭代的元素
可以使用<foreach>标签遍历列表,或者数组,也可以使用#{list[0]} #{array[2]}指定下标获取相应的值方式
传入的参数是map集合
<select id="maparg" resultType="user">
select * from users where name=#{map.name} AND password=#{map.password}
</select>
user maparg(@Param("map") HashMap<String ,Object>map);
获取map集合中的值,为map.key方式,相当于map.get("key")
#{ } 经过预编译,相当于?
${ } 相当于在编译时直接像字符串那样拼接,所以能出现在SQL语句的任意地方,比如from 之后
动态SQL
if
choose (when, otherwise) 选择其中的一个条件
<where> 如果所有的if条件都不匹配,那么采用第一种方式就会导致查询错误,而用where标签,当if匹配后,自动拼接where
<if>
</if>
</where>
<set> set标签同理,更新的时候,条件有时,自动添加set值
<if>
</if>
</set>
trim (where, set)可以自定义标签
<select id="coll" resultType="int">
select count(title) from collections where
user=#{one} <if test="two!=null">
OR user=#{two}
</if>
</select>
Integer coll(@Param("one") String one,@Param("two") String two);
<select id="read" resultType="int">
select count(*) from users,collections
where users.name=user
<choose>
<when test="title!=null and user!=null">
AND collections.title=#{title} AND users.name=#{user}
</when>
<when test="user!=null and title==null">
AND users.name=#{user}
</when>
<otherwise>
AND collections.title=#{title}
</otherwise>
</choose>
</select>
Integer read(@Param("title") String title,@Param("user") String user);
第二种方式 基于注解加上映射器接口类,没有映射文件。
@Insert("insert into author (name,password,pen_name) values(#{name},#{pa},#{pen})")
void insertAuthor(@Param("name") String name,@Param("pa") Integer password, @Param("pen") String pen);
@Select("select count(*) from author")
int allauthor();
mybatis的注解有
@Insert
@Update
@Delete
@Select
@ResultType
@Results <resultMap>高级结果映射
@ConstructorArgs <constructor>
@Arg <arg><idArg> id 属性是布尔值,来标识用于比较的属性,和<idArg> XML 元素相似
@TypeDiscriminator <discriminator>
@Case <case>
@Result <result><id>id 属性是布尔值,来标识用于比较的属性,和<idArg> XML 元素相似
@One <association>
@Many <collection>
@Results(id = "userResult", value = {
@Result(property = "id", column = "uid", id = true),
@Result(property = "firstName", column = "first_name"),
@Result(property = "lastName", column = "last_name")
})
@Select("select * from users where id = #{id}")
User getUserById(Integer id);
@Results(id = "companyResults")
@ConstructorArgs({
@Arg(column = "cid", javaType = Integer.class, id = true),
@Arg(column = "name", javaType = String.class)
})
@Select("select * from company where id = #{id}")
Company getCompanyById(Integer id);
ResultMap高级结果映射
constructor - 用于在实例化类时,注入结果到构造方法中
idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
arg - 将被注入到构造方法的一个普通结果
id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
result – 注入到字段或 JavaBean 属性的普通结果
association – 一个复杂类型的关联;许多结果将包装成这种类型嵌套结果映射 – 关联本身可以是一个 resultMap 元素,或者从别处引用一个
collection – 一个复杂类型的集合 嵌套结果映射 – 集合本身可以是一个 resultMap 元素,或者从别处引用一个
discriminator – 根据结果值来决定使用哪个 resultMap
case – 基于某些值的结果映射
嵌套结果映射 – case 本身可以是一个 resultMap 元素,因此可以具有相同的结构和元素,或者从别处引用一个
constructor标签,定义了调用结果类的构造函数,并安装构造函数的参数赋予相应的值。
result标签,给指定SQL查询结果的列值 赋值给 结果类属性
association 通常给结果类的对象属性赋值
collection 通常给结果类的集合属性赋值
<resultMap id="detailedBlogResultMap" type="Blog">
<constructor>
<idArg column="blog_id" javaType="int"/>
</constructor>
<result property="title" column="blog_title"/>
<association property="author" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
</association>
<collection property="posts" ofType="Post"> property结果类的集合属性 ofType结果类的集合中的子元素属性
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<association property="author" javaType="Author"/>
<collection property="comments" ofType="Comment">
<id property="id" column="comment_id"/>
</collection>
<collection property="tags" ofType="Tag" >
<id property="id" column="tag_id"/>
</collection>
<discriminator javaType="int" column="draft">
<case value="1" resultType="DraftPost"/>
</discriminator>
</collection>
</resultMap>
mybaits的两个内置参数
_parameter代表全部的参数,多个参数会封装map
_databaseId代表数据库的别名,如果设置了
如何使用mybatis的映射文件那,按照我的理解,如果是update,insert,delete,可以使用注解的方式,而不是映射文件
而select,可以分两种情况,第一是查询的结果非常简单,是基本的数据类型,用不到resultMap,也可以使用注解,
但是如果查询使用到了resultMap,最好使用映射文件,比较那样更加地直观。
还有一种情况,就是如果SQL语句有很多重合的地方,或者想要用到动态SQL,这个情况是必须使用映射文件。
一级缓存,本地缓存 sqlSession级别
二级缓存
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
当你设置readOnly=true的时候,cache里面存放对象引用,用户A从cache里面取出对象之后,如果A对对象进行了修改,
其他用户B再从cache取出对象,则会发现对象已经被修改。设置ReadOny=True的目的是:告诉用户不要从缓存中取出之后,对对象进行修改
readOnly只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。
cache里面存放对象的序列化,用户A从cache里面取出对象之后,如果A对对象进行了修改,
其他用户B再从cache取出对象,对象是不会变的。设置ReadOny=False的目的是:告诉用户从缓存中取出之后,可以对对象进行修改,而不影响cache里面的对象。
一级缓存无过期时间,只有生命周期
二级缓存有过期时间,但没有后台线程进行检测,而是这个cache的过期时间,是flushInterval,意味着整个清空缓存cache.