微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

mybatis

mybatis

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

​ 持久层框架,是一个不完全的ORM框架,sql语句需要程序员自己进行编写,mybatis有输入输出映射。

mybatis框架使用步骤:

1、配置mybatis配置文件sqlMaprConfig.xml(名称不固定);

2、通过配置文件加载mybatis运行环境,创建sqlSessionFactory会话工厂(sqlSessionFactory实际中按照单例管理);

3、通过sqlSessionFactory创建sqlSession会话(sqlSession是面向用户的接口,实现对象是线程不安全的,建议sqlSession的使用场合是在方法体内);

4、调用sqlSession的方法去操作数据库(如果需要提交事务,则必须调用sqlSession的commit()方法);

5、释放资源,关闭sqlSession。

1、Configuration(配置文件

1-1、db.properties(数据库连接配置)

oracle

jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:@localhost:1521:orcl
jdbc.username=scott
jdbc.password=tiger

MysqL

jdbc.driver=com.MysqL.jdbc.Driver
jdbc.url=jdbc:MysqL://localhost:3306/MysqL
jdbc.username=root
jdbc.password=root

1-2、sqlMapperConfig.xml(全局配置)

<?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>
	<!-- 加载外部的jdbc.properteis文件 -->
	<properties resource="jdbc.properties"></properties>
	
	<typeAliases>
		<!--单个java类进行配置  -->
		<typeAlias type="com.upinthewind.pojo.User"/>
		<typeAlias type="com.upinthewind.pojo.Book"/>
		<typeAlias type="com.upinthewind.util.PageBean"/>
	
    	<!-- 批量定义别名,指定包名,此时pojo类的别名是pojo类的类名首字母大写或小写都行 -->
    	<package name="com.upinthewind.dao"/>
		<package name="com.upinthewind.pojo"/>
		<package name="com.upinthewind.util"/>
	</typeAliases>
	
	<environments default="development">
		<environment id="development">
			<!-- 使用JDBC的事务管理方式 -->
			<transactionManager type="JDBC"></transactionManager>
			<!-- 使用mybatis自己的连接池 -->
			<dataSource type="POOLED">
	 			<property name="driver" value="${jdbc.driver}"/>
				<property name="url" value="${jdbc.url}"/>
				<property name="username" value="${jdbc.username}"/>
				<property name="password" value="${jdbc.password}"/>
			</dataSource>
		</environment>	
	</environments>
	
	<!--加载sql映射文件-->
	 <mappers>
        <!--批量注册  -->
			<package name="com.upinthewind.dao"/>
			
		<!--单个mapper注册-->
			<mapper class="com.upinthewind.dao.UserDaoMapper"/>
			<mapper resource="com/upinthewind/dap/UserDaoMapper.xml"/>
			<mapper url=""/> 
     </mappers>
</configuration>

1-3、xxxMapper.xml(映射文件

<?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,namespace的值习惯上设置成包名+sql映射文件名,这样就能够保证namespace的值是唯一的例如:
	namespace="me.gacl.mapping.userMapper"
	就是me.gacl.mapping(包名)+userMapper(userMapper.xml文件去除后缀)
-->
<mapper namespace="me.gacl.mapping.userMapper">

    <!-- 自定义返回结果集 -->
    <resultMap type="com.upinthewind.pojo.Book" id="bookResultMap">
    <!--
        <id column="表的主键字段" jdbcType="字段类型" property="映射pojo对象的主键属性" />
        <result column="表的字段" jdbcType="字段类型" property="映射到pojo对象的一个属性"/>
    -->
        <id column="bookno" property="bookno"/>
        <result column="bookname" property="bookname"/>
        <result column="author" property="author"/>
        <result column="cps" property="cps"/>
        <result column="cpdate" property="cpdate"/>
        <result column="kucun" property="kucun"/>

    <!--
        association 用与映射关联查询的单个对象信息 
        property	要将关联查询的对象信息映射到book对象的哪个属性
        <id column="主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" />
        <result column="表的字段" jdbcType="字段类型" property="集合中的pojo对象的属性" />
    -->
        <association property="booktype" javaType="com.upinthewind.pojo.BookType">
            <id column="typeno" property="typeno"/>
            <result column="typename" property="typename"/>
        </association>
	</resultMap>

<!-- 根据id查询得到一个user对象-->
    <!-- 
        id:"queryUser",id属性值必须是唯一的,不能够重复
        parameterType:指明查询时使用的参数类型
        resultType:指明查询返回的结果集类型,User类就是users表所对应的实体类
    -->
    <select id="queryUser" parameterType="int" resultType="com.upinthewind.pojo.User">
    	select * from users where id=#{id}
    </select>
</mapper>

2、sqlSession(sql会话)

2-1、sqlSessionFactoryBuilder

​ 通过sqlSessionFactoryBuilder创建sqlSessionFactory会话工厂

​ 将sqlSessionFactoryBuilder当成工具使用即可,不必使用单例管理sqlSessionFactoryBuilder

​ 在需要创建sqlSessionFactory时,只需要new一次sqlSessionFactoryBuilder即可

2-2、sqlSessionFactory

​ 通过sqlSessionFactory创建sqlSession,使用单例管理sqlSessionFactory(工厂一创建,只使用一个实例)

​ mybatis和spring整合后,使用单例模式管理sqlSessionFactory

2-3、sqlSession

​ 是一个面向用户(程序员)的接口

sqlSession提供了很多操作数据库方法

sqlSession是线程不安全的,在sqlSession实现类中除了有接口的方法(操作数据库方法),还有数据域属性

sqlSession最佳使用场合是在方法体中,定义成局部变量使用

public class MybatisUtil {
	//饿汉设计模式
	private static MybatisUtil mu = new MybatisUtil();
	private sqlSessionFactory ssf;//会话工厂
	/**
	 * 构造方法创建会话工厂对象
	 */
	private MybatisUtil() {
		InputStream is = MybatisUtil.class.getClassLoader().getResourceAsstream("sqlMapperConfig.xml");
		ssf = new sqlSessionFactoryBuilder().build(is);
	}
	/**
	 * 得到该单例模式的单例
	 * @return
	 */
	public static MybatisUtil init() {
		return mu;
	}
	/**
	 * 得到与数据库的会话
	 * @return
	 */
	public sqlSession getsqlSession() {
		return ssf.openSession();
	}
}

3、sqlMapperConfig.xml(全局配置文件

3-1、properties(属性

将jdbc的连接参数单独配置在properties文件中,只需要在sqlMapperConfig.xml中加载properties中定义的属性值,在sqlMapperConfig中不需要对数据库连接参数进行硬编码。同时方便管理数据库连接参数。

特性:

属性加载顺序

1、在properties元素体内定义的属性优先被读取

2、然后读取properties中resource或者url引入的外部属性,会覆盖已存在的同名属性

3、最后读取parameterType传递的属性值,会覆盖同名属性

建议:

1、不要在properties中定义属性值,将属性定义在properties文件

2、properties文件中的定义属性名要有一定的特殊性,如:jdbc.username

<!-- 引入外部db连接配置文件 -->
<properties resource="db.properties"></properties>
<!-- 也可以用property设置替换属性 --> 
<properties> 
	<property name="url" value="jdbc:MysqL://localhost:3306/tangwenmingdb"/> 
	<property name="user" value="root"/> 
	<property name="password" value="root"/> 
	<property name="driverClass" value="com.MysqL.jdbc.Driver"/> 
</properties>

3-2、settings(全局参数配置)

<settings> 
    <!-- 所有映射器中配置的缓存的全局开关。认值true --> 
    <setting name="cacheEnabled" value="true" />
    
    <!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。认值false --> 
    <setting name="lazyLoadingEnabled" value="true" />
    
    <!-- 是否允许单一语句返回多结果集(需要兼容驱动)。认值true -->
    <setting name="multipleResultSetsEnabled" value="true" />
    
    <!-- 使用列标签代替列名。不同的驱动在这方面会有不同的表现,认值true --> 
    <setting name="useColumnLabel" value="true" />
    
    <!-- 允许 JDBC 支持自动生成主键,需要驱动兼容。认值false --> 
    <setting name="useGeneratedKeys" value="false" />
    
    <!-- 
    	指定 MyBatis 应如何自动映射列到字段或属性。 
            NONE 表示取消自动映射;
            PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。
            FULL 会自动映射任意复杂的结果集(无论是否嵌套)。 
    --> 
    <!-- 认值PARTIAL --> 
    <setting name="autoMappingBehavior" value="PARTIAL" /> 
    <setting name="autoMappingUnkNownColumnBehavior" value="WARNING" />
    
    <!-- 
    	配置认的执行器。
    		SIMPLE 就是普通的执行器;
    		REUSE 执行器会重用预处理语句(prepared statements); 
    		BATCH 执行器将重用语句并执行批量更新。认SIMPLE
    --> 
    <setting name="defaultExecutorType" value="SIMPLE" />
    
    <!-- 设置超时时间,它决定驱动等待数据库响应的秒数。 --> 
    <setting name="defaultStatementTimeout" value="25" /> 
    <setting name="defaultFetchSize" value="100" />
    
    <!-- 允许在嵌套语句中使用分页(RowBounds)认值False --> 
    <setting name="safeRowBoundsEnabled" value="false" />
    
    <!-- 是否开启自动驼峰命名规则映射,列名 A_COLUMN->属性名 aColumn的类似映射。 认false --> 
    <setting name="mapUnderscoreToCamelCase" value="false" />
    
    <!--
    	MyBatis利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 
    	若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 sqlSession的不同调用将不会共享数据。 	--> 
    <setting name="localCacheScope" value="SESSION" />
    
    <!-- 
    	当没有为参数提供特定的 JDBC 类型时,为空值指定JDBC类型。
   		某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 	--> 
    <setting name="jdbcTypeForNull" value="NULL" /> 
    
    <!-- 指定哪个对象的方法触发一次延迟加载。 --> 
    <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString" />
    </settings>

3-3、typeAliases(别名)

在mapper中定义了很多的statement需要指定parameterType的类型,以及resultType指定的类型,写全路径不方便进行开发,则可以在mapper.xml中定义parameterType和resultType别名,方便开发。

mybatis支持的别名​

别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
map Map

自定义别名

​ type:类型的路径

​ alias:别名

单个定义别名

<typeAliases>
    <!-- 这样定义后就可以用city来代替整个City类全路径了-->
    <typeAlias alias="user" type="com.upinthewind.pojo.User"/>
</typeAliases>

批量定义别名

<typeAliases>
    <!-- 批量定义别名,指定包名,此时pojo类的别名是pojo类的类名首字母大写或小写都行 -->
    <package name="com.upinthewind.pojo"/>  
</typeAliases>

3-4、typeHandlers(类型处理器)

mybatis的typeHandlers完成jdbc类型和java类型的转换

认类型处理器

类型处理器 Java 类型 JDBC 类型
BooleanTypeHandler java.lang.Boolean, boolean 数据库兼容的 BOOLEAN
ByteTypeHandler java.lang.Byte, byte 数据库兼容的 NUMERIC 或 BYTE
ShortTypeHandler java.lang.Short, short 数据库兼容的 NUMERIC 或 SHORT INTEGER
IntegerTypeHandler java.lang.Integer, int 数据库兼容的 NUMERIC 或 INTEGER
LongTypeHandler java.lang.Long, long 数据库兼容的 NUMERIC 或 LONG INTEGER
FloatTypeHandler java.lang.Float, float 数据库兼容的 NUMERIC 或 FLOAT
DoubleTypeHandler java.lang.Double, double 数据库兼容的 NUMERIC 或 DOUBLE
BigDecimalTypeHandler java.math.BigDecimal 数据库兼容的 NUMERIC 或 DECIMAL
StringTypeHandler java.lang.String CHAR, VARCHAR
ClobReaderTypeHandler java.io.Reader -
ClobTypeHandler java.lang.String CLOB, LONGVARCHAR
NStringTypeHandler java.lang.String NVARCHAR, NCHAR
NClobTypeHandler java.lang.String NCLOB
BlobInputStreamTypeHandler java.io.InputStream -
ByteArrayTypeHandler byte[] 数据库兼容的字节流类型
BlobTypeHandler byte[] BLOB, LONGVARBINARY
DateTypeHandler java.util.Date TIMESTAMP
DateOnlyTypeHandler java.util.Date DATE
TimeOnlyTypeHandler java.util.Date TIME
sqlTimestampTypeHandler java.sql.Timestamp TIMESTAMP
sqlDateTypeHandler java.sql.Date DATE
sqlTimeTypeHandler java.sql.Time TIME
ObjectTypeHandler Any OTHER 或未指定类型
EnumTypeHandler Enumeration Type VARCHAR-任何兼容的字符串类型,存储枚举的名称(而不是索引)
EnumOrdinalTypeHandler Enumeration Type 任何兼容的 NUMERIC 或 DOUBLE 类型,存储枚举的索引(而不是名称)。

自定义类型处理器

<update id="update" parameterType="twm.mybatisdemo.pojo.User"> 
	update user set 
		username=#{username},
		password=#{password},
		address=#{address} 
	where id=#{id} 
</update>

public class Address { 
	String province; 
	String city; 
	public Address() {} 
	public Address(String province, String city) { 
		this.province = province; 
		this.city = city; 
	} 
	//getter and setter...... 
}

问题:

​ pojo.User类中的address字段并不是String类型,而是一个自定义Address类型,

​ address字段需要传递给#{address},而address字段是Address类型的,MyBatis并不知道该怎样来处理这个类型的对象。因此,需要创建一个自定义的类型处理器(TypeHandler)了

步骤:

​ 1、创建类型处理器

class AddresstypeHandler extends BaseTypeHandler<Address>{
	//通过ide自动生成代码,可以看到父类BaseTypeHandler有四个方法需要我们实现
	//包括三个get方法一个set方法。
}

​ 2、实现get方法
​ 三个get方法都是用于将数据库获得的记录集里的address字段转成java Address类型的对象。
​ 所以我们首先给Address类增加一个构造方法,用途:根据字符串生成一个实例对象。

//假设我们存储在db中的字符串是以","号分隔省市关系的
public Address(String address) {  
    if (address != null) {  
        String[] segments = address.split(",");  
        if (segments.length > 1) {  
            this.province = segments[0];
            this.city = segments[1];  
        } 
        else if (segments.length > 0) {  
            this.city = segments[0];  
        }  
    }  
}

​ 然后实现AddresstypeHandler类中的三个get方法

@Override
public Address getNullableResult(ResultSet rSet, String columnName)
        throws sqlException {
    return new Address(rSet.getString(columnName));
}

@Override
public Address getNullableResult(ResultSet rSet, int columnIndex)
        throws sqlException {
    return new Address(rSet.getString(columnIndex));
}

@Override
public Address getNullableResult(CallableStatement cStatement, int columnIndex)
        throws sqlException {
    return new Address(cStatement.getString(columnIndex));
}

​ 3、实现set方法

​ set方法是用来将java类型转成数据库存储的类型。
​ 这里我们先实现一下Address类的toString()方法(如果toString另有它用,那么就另外用一个方法名)

@Override
public String toString() {
    return this.province + "," + this.city;
}
@Override
public void setNonNullParameter(PreparedStatement pStatement, int index,
        Address address, JdbcType jdbcType) throws sqlException {
    pStatement.setString(index, address.toString());
}

​ 然后实现AddresstypeHandler类中的setNonNullParameter

​ 4、在myBatis配置文件注册该类

<!-- 注册自定义类型处理器 -->
<typeHandlers>
    <typeHandler handler="twm.mybatisdemo.type.AddresstypeHandler" />
</typeHandlers>

3-5、objectFactory(对象工厂)

3-6、plugins(插件

3-7、environments(环境配置)

<environments default="development">	
    <environment id="development">
    <!-- 使用JDBC的事务管理方式 -->
    	<transactionManager type="JDBC"></transactionManager>
    <!-- 使用mybatis自己的连接池 -->
        <dataSource type="POOLED">
            <property name="driver" value="${jdbc.driver}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </dataSource>
    </environment>
</environments>

3-9、transactionManager(事务管理器)

mybatis提供了两种事务管理器,分别是:JDBC , MANAGED

JDBC:这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务范围。

MANAGED :这个配置从来都不提交和回滚一个连接,而是让容器来管理事务的整个生命周期(比如JEE应用服务的上下文)。认情况下他会关闭连接,然而一些容器并不希望这样,因此需要将closeConnection属性设置为false来阻止它认的关闭行为。

<transactionManager type="MANAGED">
	<property name="closeConnection" value="false"/>
</transactionManager>

3-10、dataSource(数据源)

dataSource元素使用标准的JDBC数据源接口来配置JDBC连接对象的资源。mybatis提供了3种数据源类型,分别是:POOLED,UNPOOLED,JNDI

**UNPOOLED:**表示不支持数据源连接池。这样每次请求都会进行打开和关闭数据库连接操作,性能上会有些损耗。但对一些没有性能要求的程序来说使用起来较方便,配置少。

UNPOOLED 类型的数据源仅仅用来配置以下 5 种属性:

driver 这是 JDBC 驱动的 Java 类的完全限定名(如果你的驱动包含,它也不是 数据源类)。
url 这是数据库的 JDBC URL 地址。
username 登录数据库用户名。
password 登录数据库的密码。
defaultTransactionIsolationLevel 认的连接事务隔离级别。 

**POOLED:**表示支持JDBC数据源连接池。这样可避免每次请求都要创建新的连接。

属性除了UNPOOLED的那5个,另外还有以下属性

poolMaximumActiveConnections:任意时间的最大活动(正在使用)连接数量认值:10
poolMaximumIdleConnections :任意时间的最大空闲(没有使用)连接数。
poolMaximumCheckoutTime:再被强制返回之前,池中连接被checkout时间,认值2W毫秒 即20s
poolTimetoWait:获取连接超时时间。认:2W毫秒即20s。如果超时,它会给连接池打印状态日志并重新尝试获取

**JNDI:**表示支持外部数据源连接池。如mybatis与tomcat整合配置jndi

initial_context 
	用 来 从 初 始 上 下 文 中 寻 找 环 境 ( 也 就 是initialContext.lookup(initial——context) 
	这是个可选属性,如果被忽略,那么 data_source 属性将会直接以 initialContext 为背景再次寻找。 data_source
	这是引用数据源实例位置的上下文的路径。
	它会以由 initial_context 查询返回的环境为背景来查找
	如果 initial_context 没有返回结果时,直接以初始 上下文为环境来查找 

3-11、mappers(映射注册)

mappers映射文件注册

<!-- 第一种方式: 一个个指定接口文件配置文件位置--> 
 <mappers>
	<mapper class="com.upinthewind.dao.UserDaoMapper"/>
	<mapper resource="com/upinthewind/dap/UserDaoMapper.xml"/>
	<mapper url=""/>
</mappers> 
<!-- 第二种方式: 指定包加载。可指定多个包 -->
 <mappers>
    <package name="com.upinthewind.dao" />
</mappers> 

4、mapper(映射文件

mybatis编写dao层:

4-1、原始dao层编写方法

​ 需要程序员编写dao层的接口和实现类

​ 需要在dao层的实现类中注入sqlSessionFactory工厂

4-2、mapper代理方式

​ 只需要编写mapper接口(即dao层的接口)

​ 编写mapper.xml(映射文件)和mapper.java(需遵循相应的开发规范)

​ 开发规范:

​ (1)、在mapper.xml中namespace属性值为mapper接口全路径

<mapper namespace="me.gacl.mapping.userMapper">

​ (2)、mapper接口中的方法名要与mapper.xml中的statement的id一致

​ (3)、mapper接口中方法的输入参数要与mapper.xml对应的statement的parameterType的类型一致

​ (4)、mapper接口中方法的返回值要与mapper.xml对应的statement的resultType的类型一致

​ mapper代理方式调用方法

    sqlSession ss = MybatisUtil.init().getsqlSession();//得到sqlSession
    BookMapper bd = ss.getMapper(BookMapper.class);//mybatis动态创建接口的实现类
   	bd.deleteBookByBookNo(59);//调用方法
    ss.commit();
    ss.close();

5、动态sql

mybatis核心对sql语句进行灵活操作,通过表达式对sql语句进行判断、拼接、组装

5-1、where if

<!--多条件查总记录数  -->
	<select id="queryAllRecords" parameterType="Condition" resultType="int">
		select count(1) from tbl_book
		<where>
			<if test="bookName!=null and bookName!=''">
				and bookName like concat('%',concat(#{bookName},'%'))
			</if>
			<if test="typeNo!=null and typeNo!=0">
				and typeNo=#{typeNo}
			</if>
			<if test="beginTime!=null">
				and cpDate &gt; #{beginTime}
			</if>
			<if test="endTime!=null">
				and cpDate &lt; #{endTime}
			</if>
		</where>
	</select>

5-2、choose, when, otherwise

不想应用到所有的条件语句,而只想从中择其一项

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>

5-3、if set

当 update 语句中没有使用 if 标签时,如果有一个参数为 null,都会导致错误

当在 update 语句中使用if标签时,如果前面的if没有执行,则或导致逗号多余错误。使用set标签可以将动态的配置 SET 关键字,并剔除追加到条件末尾的任何不相关的逗号。使用 if+set 标签修改后,如果某项为 null 则不进行更新,而是保持数据库原值。

<!--  if/set(判断参数) - 将实体 User类不为空的属性更新 -->  
<update id="updateUser_if_set" parameterType="com.pojo.User">  
    UPDATE user  
    <set>  
        <if test="username!= null and username != '' ">  
            username = #{username},  
        </if>  
        <if test="sex!= null and sex!= '' ">  
           sex = #{sex},  
        </if>  
        <if test="birthday != null ">  
            birthday = #{birthday},  
        </if>
    </set>
    WHERE user_id = #{userid};      
</update>

5-4、foreach

处理传入参数为数组或list集合,使用foreach解析

mapper.xml

<!--
    item表示集合中每一个元素进行迭代时的别名,
    index指 定一个名字,用于表示在迭代过程中,每次迭代到的位置,
    open表示该语句以什么开始,
    separator表示在每次进行迭代之间以什么符号作为分隔 符,
    close表示以什么结束。
-->

<select id="queryBuBookNos" parameterType="java.util.List" resultType="Book">
	select * from tbl_book where bookNo in 
	
	<foreach collection="list" index="index" item="item_no" open="(" separator="," close=")" >
			#{item_no}
	</foreach>
</select>


<select id="queryBuBookNos" parameterType="java.util.Array" resultType="Book">
	select * from tbl_book where bookNo in 
	
	<foreach collection="array" index="index" item="item_no" open="(" separator="," close=")" >
			#{item_no}
	</foreach>
</select>

mapper接口

List<Book> queryBuBookNos(List<Integer> list);

测试

@Test
public void queryBuBookNostest() {
    sqlSession ss = MybatisUtil.init().getsqlSession();
    BookMapper bd = ss.getMapper(BookMapper.class);
    List<Integer> list = new ArrayList<>();
    //226 95 102 103 104
    list.add(226);
    list.add(95);
    list.add(102);
    list.add(103);
    list.add(104);
    List<Book> books = bd.queryBuBookNos(list);
    for (Iterator it = books.iterator(); it.hasNext();) {
        Book book = (Book) it.next();
        System.out.println(book);
    }
}

5-5、sql片段

定义sql片段

<!--sql片段  -->
	<sql id="select_by_condition">
		<if test="t.bookName!=null and t.bookName!=''">
				and bookName like concat('%',concat(#{t.bookName},'%'))
			</if>
			<if test="t.typeNo!=null and t.typeNo!=0">
				and typeNo=#{t.typeNo}
			</if>
			<if test="t.beginTime!=null">
				and cpDate &gt; #{t.beginTime}
			</if>
			<if test="t.endTime!=null">
				and cpDate &lt; #{t.endTime}
			</if>
	</sql>

引用sql片段

<!--多条件分页查询  -->
	<select id="queryBookByPage" parameterType="PageBean" resultType="Book">
		select * from (select b.*,rownum r from tbl_book b
		<where>
			<!--引用sql片段-->
			<include refid="select_by_condition"></include>
		</where>
		)where r &gt; #{beginRecords} and r &lt;= #{endRecords}
	</select>

6、高级映射(resultMap)

resultMap可以实现延迟加载

6-1、一对一(association)

<!--
    resultMap映射配置
    column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性
-->
	<resultMap type="com.upinthewind.pojo.Book" id="bookResultMap">
		
		<id column="bookno" property="bookno"/>
		<result column="bookname" property="bookname"/>
		<result column="author" property="author"/>
		<result column="cps" property="cps"/>
		<result column="cpdate" property="cpdate"/>
		<result column="kucun" property="kucun"/>
		
		<!--
			association 用与映射关联查询的单个对象信息 
			property	要将关联查询的对象信息映射到book对象的哪个属性
		 -->
		<association property="booktype" javaType="com.upinthewind.pojo.BookType">
			<id column="typeno" property="typeno"/>
			<result column="typename" property="typename"/>
		</association>
		
	</resultMap>

	<select id="queryAllBook" resultMap="bookResultMap">
		SELECT bookno,bookname,b.typeno,author,cps,cpdate,kucun,typename 
		FROM tbl_book b INNER JOIN tbl_type t ON b.typeno=t.typeno  
	</select>

6-2、一对多(collection)

一个实体类包含另一个实体类的集合

Role角色实体类

public class Role {
	private Integer rid;
	private List<Power> powers;
	private String rname;

Power权限实体类

public class Power {
	private Integer pid; 
	private String pcontent; 
	private String url;

RoleDaoMapper.xml

<mapper namespace="com.upinthewind.dao.RoleDaoMapper">
	<!--自定义结果集-->
	<resultMap type="role" id="roleAndPower">
		<id column="rid" property="rid"/>
		<result column="rname" property="rname"/>
		
		<!--role中包含power的集合-->
		<collection property="powers" column="rid" ofType="power" 	
			select="com.upinthewind.dao.PowerDaoMapper.queryPowerById">
		</collection>
	</resultMap>
	
	<select id="queryRoleById" parameterType="int" resultMap="roleAndPower">
		select * from tbl_role where rid = #{rid}
	</select>
</mapper>

PowerDaoMapper.xml

<mapper namespace="com.upinthewind.dao.PowerDaoMapper">
	
	<select id="queryPowerById" parameterType="int" resultType="Power">
		select p.* from tbl_power p inner join role_power rp on p.pid = rp.pid 
		where rp.rid=#{id}
	</select>
</mapper>

6-3、多对多(collection)

7、延迟加载

association和collection具备延迟加载的功能,当需要某个条件时才进行相关的查询–按需查询

多表关联查询时,先查一张表,在按需求查询其他表的数据,即是延迟加载。使用assocation中的select去加载statement的id,如果当前mapper.xml中没有该id需要在id前面加上其他mapper.xml的namespace

7-1、assocation

BookDaoMapper.xml

<mapper namespace="com.upinthewind.dao.BookDaoMapper">
<!--
    resultMap映射配置
    column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性
-->
	<resultMap type="com.upinthewind.pojo.Book" id="bookResultMap">
	
		<id column="bookno" property="bookno"/>
		<result column="bookname" property="bookname"/>
		<result column="author" property="author"/>
		<result column="cps" property="cps"/>
		<result column="cpdate" property="cpdate"/>
		<result column="kucun" property="kucun"/>
		
		<!--
			association 用与映射关联查询的单个对象信息 
			property	要将关联查询的对象信息映射到book对象的哪个属性
			column	根据哪个字段进行关联查询(外键)
			select	关联查询的mapper.xml的namespace.id
		 -->
        <association property="booktype" javaType="BookType" column="typeno"	
                select="com.upinthewind.dao.BookTypeDaoMapper.queryTypeByNo">
        </association>
	</resultMap>

	<select id="queryAllBook" resultMap="bookResultMap">
		select * from tbl_book
	</select>
</mapper>		

BookTypeDaoMapper.xml

<mapper namespace="com.upinthewind.dao.BookTypeDaoMapper">
	<select id="queryTypeByNo" parameterType="int" resultType="BookType">
		select * from tbl_type where typeNo = #{typeNo}
	</select>
</mapper>

7-2、collection

RoleDaoMapper.xml

<mapper namespace="com.upinthewind.dao.RoleDaoMapper">
	<!--自定义结果集-->
	<resultMap type="role" id="roleAndPower">
		<id column="rid" property="rid"/>
		<result column="rname" property="rname"/>
		
		<!--role中包含power的集合-->
		<collection property="powers" column="rid" ofType="power" 	
			select="com.upinthewind.dao.PowerDaoMapper.queryPowerById">
		</collection>
	</resultMap>
	
	<select id="queryRoleById" parameterType="int" resultMap="roleAndPower">
		select * from tbl_role where rid = #{rid}
	</select>
</mapper>

PowerDaoMapper.xml

<mapper namespace="com.upinthewind.dao.PowerDaoMapper">
	
	<select id="queryPowerById" parameterType="int" resultType="Power">
		select p.* from tbl_power p inner join role_power rp on p.pid = rp.pid 
		where rp.rid=#{id}
	</select>
</mapper>

8、查询缓存

如果缓存中有数据,则不需要去数据库进行获取,用于减轻数据库的压力,提高数据库性能

8-1、一级缓存(sqlSession)

1、sqlSession对象有一个HashMap数据结构,用于缓存数据,不同sqlSession对象的HashMap之间互不影响。

2、mybatis支持一级缓存,不需要手动配置。

3、如果sqlSession执行了commit方法,则会清空一级缓存,是为了保证缓存区内的信息是最新的,避免出现脏读。

4、正常开发,是将mybatis与spring整合开发,事务控制在service层,一个service方法可以调用多个mapper。service方法执行时,开启事务,创建sqlSession对象,结束时关闭sqlSession。

8-2、二级缓存(Mapper)

1、一级缓存在方法结束时,会关闭sqlSession,必然会清空一级缓存

2、多个sqlSession去操作同一个Mapper的sql语句,多个sqlSession操作数据库得到的数据会存在二级缓存区域,二级缓存是跨sqlSession的,是多个sqlSession共用的。

3、二级缓存与一级缓存区别:二级缓存区(namespace)更大,是所有访问该Mapper的sqlSession共享

4、执行commit,清空二级缓存

使用

1、全局配置文件中开启二级缓存(认为开启)

<setting name="cacheEnabled" value="true"/>

2、在Mapper.xml中开启二级缓存

<!--
	type : 指定cache接口的实现类型,mybatis认使用PerpetualCache
-->
<cache type=""/>

3、该Mapper对应的实体类要实现序列化(为了将缓存数据取出,反序列化)

implements Serializable

8-3、分布式缓存

对缓存数据进行集中管理,使用分布式缓存框架(redis、memcached、ehcache)。

mybatis无法实现分布式管理,需要与其它分布式缓存框架整合使用。

实现cache接口

9、注解方式

9-1、单表查询

public interface UserDaoMapper {
	
	User queryUser(User user);
	
	@Insert("INSERT INTO tbl_user VALUES(seq_user.nextval, #{uname}, #{pwd}, #{role.rid})")
	int addUser(User user);
	
	@Delete("delete from tbl_user where uno = #{uno}")
	int deleteUser(Integer uno);
}

9-2、一对一

public interface IPersonDao {
	@Select("select * from person where pid = #{pid}") 
	@Results({
            @Result(id=true,column="pid",property="pid"),
            @Result(column="pname",property="pname"), 
            @Result(column="page",property="page"), 
            @Result(column="pid",property="card",one=@One
				(select="com.desert.dao.ICardDao.getCard",fetchType= FetchType.EAGER)) 				}) 
	public Person getPerson(int pid); 
}

9-3、一对多

public interface RelationMapper {

    @Select("select id,name from TEACHER")
    @Results({
    		@Result(id="true" property = "id",column = "id"),
            @Result(property = "name",column = "name"),
            @Result(property = "students",javaType = List.class,column ="id",
                    many = @Many(select = "com.example.mapper.RelationMapper.findStudents"))})
    List<TeacherVo> findTeacherAndStudents();

    @Select("select s.name from RELATION r,STUDENT s where s.id = r.sid and r.tid = #{tid}")
    List<Student> findStudents(Long tid);

}

10、数据库数据模型分析

1、每张表记录的数据内容

​ 分模块熟悉每张表的内容,学习系统需求(功能

2、每张表的重要字段设置

​ 非空字段、外键关联字段

3、数据库级别表与表之间的关系

​ 外键关系

4、表与表之间的业务关系

​ 分析表与表之间的业务关系时,要建立在某个业务意义基础上进行分析

逆向工程

generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="testTables" targetRuntime="MyBatis3">

        <commentGenerator>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!-- 连接数据库 -->
        <jdbcConnection driverClass="com.MysqL.jdbc.Driver"
            connectionURL="jdbc:MysqL://localhost:3306/mybatis" userId="root" password="">
        </jdbcConnection>

        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>
        <!-- targetPackage:生成po类的包名 targetProject:生成po类的位置 -->
        <javaModelGenerator targetPackage="com.mybatis.po"
            targetProject="./src">
            <property name="enableSubPackages" value="true" />
            <property name="trimstrings" value="true" />
        </javaModelGenerator>
        
        <!-- targetPackage:mapper接口文件生成的包名 targetProject:mapper接口文件生成的项目位置-->
        <sqlMapGenerator targetPackage="com.mybatis.dao"
            targetProject="./src">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        
        <!-- targetPackage:mapper映射文件生成的包名  targetProject:mapper映射文件生成的项目位置-->
        <javaClientGenerator type="XMLMAPPER"
            targetPackage="com.mybatis.dao" targetProject="./src">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <!-- 配置需要生成的表 -->
        <table tableName="user" domainObjectName="user"></table>
        <table tableName="orders" domainObjectName="orders"></table>
        <table tableName="orderdetail" domainObjectName="orderdetail"></table>
        <table tableName="items" domainObjectName="items"></table>

    </context>
</generatorConfiguration>

GeneratorsqlMap.java

public class GeneratorsqlMap {
    public void generator() throws Exception{
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        //指定逆向工程配置文件
        File configFile = new File("generatorConfig.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);
    }
    public static void main(String[] args) {
        GeneratorsqlMap generatorsqlMap = new GeneratorsqlMap();
        try {
            generatorsqlMap.generator();
        } catch (Exception e) {
            e.printstacktrace();
        }
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。