mybatis(ibatis)理解

Mybatis
MyBatis是支持普通 SQL查询,存储过程和高级映射的优秀持久层框
架。 MyBatis消除了几乎所有的 JDBC 代码和参数的手工设置以及结
果集的检索。 MyBatis使用简单的 XML或注解用于配置和原始映射
,将接口和 Java 的POJOs(Plan Old Java Objects,普通的 Java对
象)映射成数据库中的记录。

MyBatis核心

使用步骤:
1、导入jar包
2、新建一个MyBatis的配置文件,文件类型是xml,名字随便起。加上文件的dtd验证文件头,
<?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,一个用于开发环境一个用于线上环境。环境中需要配置数据源,事务管理器等信息
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mydb"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
配置文件基本完成,接下来在main方法中读取主配置文件,并创建出SqlSessionFactory对象,
读取配置文件
Reader reader = Resources.getResourceAsReader(“config.xml”);
创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
有了SqlSessionFactory对象就可以创建出session对象
SqlSession session = factory.openSession();
session.close();
在事务开始与结束之间来执行应有的操作。并在关闭事务之前提交事务
session.commit();
如果不想写这段代码来手动的提交事务,可以再常见session的时候加入一个Boolean类型的参数,表示自动提交事务。
在项目中创建一个包名为dao或者是mapper的包,然后在包中创建一个UserMapper.xml的配置文件,引入dtd文档头,
<?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属性,属性的值写成一个倾向于一个Dao类的完全限定名,最好与当前配置文件名之间具有一定的联系,比如配置文件名是UserMapper.xml,可以将其namespace属性值定义为当前所在的包名加上UserDao这个类名组成完全限定名。根节点中就可以直接写平常使用的sql语句了,根据增伤改查的不同。分别对应四个节点分别是insert/delete/update/select。
<select id="findById" parameterType="int" resultType="User">
select id,username,password from t_user where id = #{id}
</select>
例如上面的查询、id属性对应之前Dao类中的方法的名字,parameterType对应查询的时候传入参数的类型,resultType对应查询结果的结果及类型也可以是返回值类型,查询语句的限制条件处使用#{}的方式来括起来限制条件的属性字段。
在main方法中使用的时候就可以这样用:
User user = session.selectOne("com.kaishengit.dao.UserDao.findById",45);
selectOne代表只查询一个方法中有两个参数,第一个参数是要执行的方法的名字,也是以完全定名的方式写入,精确到Mapper配置文件中的id方法的名字,第二个参数是查询的时候限制条件中的值。查询到的结果会自动封装成User对象。
在实际查询之前还要将UserMapper这样的映射文件添加到Mybatis的主配置文件中
<mappers>
<mapper resource="com/kaishengit/mybatis/mapper/usermapper.xml"/>
</mappers>
使用这种方式查询的缺点是在查询的时候要写那么长的类似于方法的完全限定名这样的字符串,因此在实际使用的时候,可以创建一个和映射文件中的namespace属性值相同的一个接口,在接口中定义这些在映射文件中定义的查询操作的方法。在dao或mapper包中创建出一个UserDao的接口在接口中定义在配置文件中写的一些类方法,方法的名字和id数字那个值的名字相同,参数类型也要和映射文件中的类型相同。返回值类型根据具体情况来决定,当查询的是一个对象的时候,可以使用一个对象来接收,当查询的是一个集合的时候,在配置文件中的结果集类型依然是User类,但是在接口中的方法中的类型为一个集合。
保存操作:
在保存之后能够像Hibernate一样获得保存之后对象的主键值,在映射文件中,save节点中增加属性,userGeneratedKeys的属性值为true,表示使用自动增长类型的主键值。keyProperty值为id代表User对象的id属性值。keyColumn用来定义列名。
在返回结果类型处,依然要写基于完全限定名的方式,那么就可以在主配置文件中写别名
<typeAliases>
<typeAlias type="com.kaishengit.poo.User" alias="User"/>
</typeAliases>
这样写的话就不用在映射文件中写那么长的结果类型的完全限定名的包名了。但是这样写的话就没增加一个pojo类就得填上一个别名,实际使用的时候可以这样写
<package name="com.kaishengit.pojo"/>
将整个pojo包中的所有实体类都纳入别名管理中。别名就是类名
执行删除操作
当查询的属性名不在表中的字段,例如表中的字段名为stuname,而实体类的属性的名字是username,那么就可以再SQL语句中起别名的形式来避免这种问题
select stuname as username from
第二种解决方式就是使用select * from 来查询
返回值类型不再用resultType类型,而是使用resultMap属性,属性值可以定义为userMap,在映射文件中创建一个resultMap的节点,type属性值依然为User,id属性值为之前定义的userMap。
<resultMap type="User" id="userMap">
<id property="id" column="id"/>
<result column="stuname" property="username"/>
<result column="password" property="password"/>
</resultMap>
column属性值为查询的结果集中数据库中的字段名,property为pojo实体类中的属性名字。

查询:
当查询的时候有多个参数的时候
第一种:
将参数封装成一个Map,将查询条件封装成一个Map
第二种:
将参数封装成一个User对象之类的pojo类的对象
第三种:
直接以参数的形式进行传递,在映射文件中不写参数类型。而在查询语句中使用#{param1}这样的形式来定义要传入的参数,不写类型,在实际使用的时候,只要传入参数的类型和数量与Sql语句中的数量和类型一致就可以了。

查询所有
当查询所有的时候结果虽然是一个List集合,但是在映射文件中的resultType属性值依然是User。

多表查询:
使用连接查询语句
由于是多表联查既不能使用resultType来表示结果类型了,要使用resultMap来表示结果集的映射关系。
<select id="findByIdWithNews" parameterType="int" resultMap="findAllUser">
SELECT t_user.id,username,password,t_news.id AS newsid,title FROM
t_user
LEFT JOIN t_news ON t_user.id = t_news.uid
WHERE t_user.id = #{id}
</select>
<resultMap type="User" id="findAllUser">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<collection property="newsList" ofType="News">
<id property="id" column="newsid"/>
<result property="title" column="title"/>
</collection>
</resultMap>

User和news之间是一对多的关系,因此使用collection来封装,property属性值为在User实体类属性中的集合属性的名字,ofType用来说明这个集合中存放的值的类型是News类型,
当是多对一的关系的时候,使用方法和一对多基本相同,由于多对一查询的时候就不是一个集合,而是i一个对象,因此使用association节点,也不再用ofType属性,而是用javaType属性。
<select id="findAll" resultType="list" resultMap="findNews" >
SELECT t_news.id,title,uid,username,PASSWORD FROM t_news
LEFT JOIN t_user ON t_news.uid = t_user.id
</select>
<resultMap type="News" id="findNews">
<id property="id" column="id"/>
<result property="title" column="title"/>
<association property="user" column="uid" javaType="User">
<id column="uid" property="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
</association>
</resultMap>

另一种查询:
现根据addrssid 来找到Address对象,进而获得userid,根据userid获取user对象,在resultMap中的association节点中的select属性,标明这个结果的查询是通过另一个select来查询到的。column用来定义根据第一条查询条件中的哪个字段值来执行第二条select语句,并作为第二条select语句的限制条件传入

示例:
<!-- 另一种查询方式,两次单表查询拼接-->
<select id="findAddressById" parameterType="int" resultMap="addressMap">
select * from address where id = #{id}
</select>

<select id="findUserByid" parameterType="int" resultMap="userMap">
select * from user where id = #{id}
</select>

<resultMap type="Address" id="addressMap">
<id column="id" property="id"/>
<result column="address" property="address"/>
<association property="user" javaType="User" select="findUserByid" column="user_id" />
</resultMap>

<resultMap type="User" id="userMap">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
</resultMap>

动态SQL
当查询的条件不确定的时候,有时候我们就需要使用动态SQL。比如我们有时要根据用户名来查询User对象,有时候可能需要根据用户名和密码来查询User对象
因此需要使用动态sql来进行查询。在实际使用的时候将查询条件封装成一个Map集合或者是一个User对象进行查询。
if
<select id="findByWhere" resultType="User">
select * from user
<where>
<if test="username != null">
username = #{username}
</if>
<if test="password != null">
and password = #{password}
</if>
</where>
</select>
choose
<select id="findByChoose" parameterType="map" resultType="User">
select * from user
<where>
<choose>
<when test="username != null">
username = #{username}
</when>
<when test="password != null">
password = #{password}
</when>
<otherwise>
</otherwise>
</choose>
</where>
</select>
where
<select id="findByWhere" resultType="User">
select * from user
<where>
<if test="username != null">
username = #{username}
</if>
<if test="password != null">
and password = #{password}
</if>
</where>
</select>
update
<update id="updateInfo" parameterType="User">
update user
<trim prefix="set" suffixOverrides="," prefixOverrides=",">
<if test="username != null">
,username = #{username}
</if>
<if test="password != null">
,password = #{password}
</if>
</trim>
where id = #{id}
</update>
foreach:
<select id="findByForeach" parameterType="list" resultType="User">
select * from user
where id in
<foreach collection="list" index="index" item="item" open="(" close=")" separator=",">
#{item}
</foreach>
</select>


缓存

<mapper namespace="com.kaishengit.mapper.NewsMapper">
<cache/>
...
</mapper>
功效如下:
• 映射语句文件中所有的select语句将被缓存
• 映射语句文件中的所有insert、update、delete语句会刷新缓存
• 缓存会使用least recentily used(LRU,最近很少使用的)算法来收回
• 根据时间间隔来刷新缓存,默认不刷新
• 缓存会存储列表集合或对象的1024个引用
• 缓存被视为read/write的缓存
更改缓存
<cache eviction="FIFO" flushInterval="60000" size="512"
readOnly="true"/>
上面配置了一个FIFO缓存,每隔60秒刷新一次缓存,存储对象或集合512个引用,而且缓存为只读缓存。

eviction回收策略
• LRU:最近最少使用的,移除长时间不被使用的对象(默认)
• FIFO:先进先出:按对象进入缓存的顺序来移除他们
• SOFT:软引用:移除基于垃圾回收器状态和软引用规则的对象
• WEAK:弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
• flushInterval(刷新间隔):可以被设置为任意的正整数
• size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行
环境的可用内存资源数目。默认值是 1024。
• readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者迒
回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
可读写的缓存会迒回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此
默认是false。


mybatis与spring整合:

1、导入myatis-spring.jar
2、新建Spring的配置文件applicationContext.xml,配置事务管理器,数据库连接池、配置mybatis的sqlSessionFactory、配置自动扫描Mapper的bean
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
>
<property name="dataSource" ref="dataSource" />
</bean>
<!-- DBCP 数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///mydb"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
<property name="initialSize" value="5"></property>
<property name="maxActive" value="20"></property>
</bean>
<bean id="sessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage"
value="com.kaishengit.entity"></property>
</bean>
<!-- 自动扫描Mapper -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name=“basePackage” value = “com.kaishengit.dao”/>
</bean>
在web.xml中配置Spring的监听器
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>

原文地址:https://www.cnblogs.com/shininguang/p/4858755.html