浅谈MyBaties

第一章——简介

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。

MyBatis的主要成员

  • Configuration        MyBatis所有的配置信息都保存在Configuration对象之中,配置文件中的大部分配置都会存储到该类中
  • SqlSession            作为MyBatis工作的主要顶层API,表示和数据库交互时的会话,完成必要数据库增删改查功能
  • Executor               MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
  • StatementHandler 封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数等
  • ParameterHandler  负责对用户传递的参数转换成JDBC Statement 所对应的数据类型
  • ResultSetHandler   负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
  • TypeHandler          负责java数据类型和jdbc数据类型(也可以说是数据表列类型)之间的映射和转换
  • MappedStatement  MappedStatement维护一条<select|update|delete|insert>节点的封装
  • SqlSource              负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
  • BoundSql              表示动态生成的SQL语句以及相应的参数信息

1、构建 SqlSessionFactory

c、每个基于MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的

b、SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得

c、可以使用Resources 工具类,从 classpath 或其他位置加载资源文件,通过 XML 文件构建 SqlSessionFactory

test. java

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

 mybatis-config.xml.java

<?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="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
   </environment>
 </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

2、获取 SqlSession

通过SqlSessionFactory获得 SqlSession 的实例。

SqlSession 包含了面向数据库执行 SQL 命令所需的方法。通过 SqlSession 实例来执行已映射的 SQL 语句。

test.java

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
//Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);

 mybatis-config.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>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
   </environment>
 </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

BlogMapper.mapper

<?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="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>

3、作用域(Scope)和生命周期

  • SqlSessionFactoryBuilder

用于创建SqlSessionFactory,一旦就不再需要它了

  • SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,通常使用单例模式或者静态单例模式。

  • SqlSession

a、每个线程都应该有它自己的 SqlSession 实例。

b、SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。

c、通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。

 

 

第二章——XML核心配置

通常放在mybatis-config.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>
    <!--环境配置,连接的数据库,这里使用的是MySQL-->
    <environments default="mysql">
        <environment id="mysql">
            <!--指定事务管理的类型,这里简单使用Java的JDBC的提交和回滚设置-->
            <transactionManager type="JDBC"></transactionManager>
            <!--dataSource 指连接源配置,POOLED是JDBC连接对象的数据源连接池的实现-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"></property>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybbs"></property>
                <property name="username" value="root"></property>
                <property name="password" value="root"></property>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="User.xml"></mapper>
    </mappers>
</configuration>

1、属性(properties)

该元素用于配置属性

这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。

 

config.properties 文件中的username 和 password ,将会由 properties 元素中设置的相应值来替换。

  • 子元素传递
<properties resource="org/mybatis/example/config.properties">
  <property name="username" value=" "/>
  <property name="password" value=" "/>
</properties>

driver 和 url 属性将会由 config.properties 文件中对应的值来替换。 

  • 动态替换
<dataSource type="POOLED">
  <property name="driver" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="${username}"/>
  <property name="password" value="${password}"/>
</dataSource>

 

2、环境配置(environments)

通过<environments>元素配置多种数据源

尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

  • 默认的环境 ID(比如:default="development")。
  • 每个 environment 元素定义的环境 ID(比如:id="development")。
  • 事务管理器的配置(比如:type="JDBC")。
  • 数据源的配置(比如:type="POOLED")。
<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <dataSource type="POOLED">
      <property name="driver" value="${driver}"/>
      <property name="url" value="${url}"/>
      <property name="username" value="${username}"/>
      <property name="password" value="${password}"/>
    </dataSource>
  </environment>
</environments>
  • transactionManager

在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):

  • JDBC – 这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务范围。
  • MANAGED – 这个配置几乎没做什么。

如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器, 因为 Spring 模块会使用自带的管理器来覆盖前面的配置。

 

  • dataSource

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。

许多 MyBatis 的应用程序将会按示例中的例子来配置数据源。然而它并不是必须的。要知道为了方便使用延迟加载,数据源才是必须的。

有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):

UNPOOLED– 这个数据源的实现只是每次被请求时打开和关闭连接

POOLED– 这种数据源的实现利用"池"的概念将 JDBC 连接对象组织起来

JNDI– 这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用

3、映射器(mappers)

用于指定MyBatis映射器(sql语句的xml文件)配置文件的位置

  • 类路径引入
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
</mappers>
  • 文件路径引入
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
</mappers>
  • 接口类引入
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
  • 包名引入
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

 

4、类型别名(typeAliases)

类型别名:为 Java 类型设置一个短的名字。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
</typeAliases>

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean

在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。

比如 domain.blog.Author 的别名为 author

<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

若有注解,则别名为其注解值。

   @Alias("author")
    public class Author {
        ...
    }
  • java类型别名
别名映射的类型
_longlong
_intint
_doubledouble
_integerint
_booleanboolean
stringString
longLong
intInteger
integerInteger
doubleDouble
booleanBoolean
dateDate
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection

 

5、设置(settings)

它们会改变 MyBatis 的运行时行为

设置名描述有效值默认值
cacheEnabled全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存。true | falsetrue
lazyLoadingEnabled

开启时,所有关联对象都会延迟加载。

特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。

true | falsefalse
aggressiveLazyLoading

当开启时,任何方法的调用都会加载该对象的所有属性。

否则,每个属性会按需加载(参考 lazyLoadTriggerMethods)。

true | falsefalse 
multipleResultSetsEnabled是否允许单一语句返回多结果集(需要驱动支持)。true | falsetrue
useGeneratedKeys允许 JDBC 支持自动生成主键。true | falseFalse
autoMappingBehavior

自动映射列到字段或属性。

NONE 表示取消自动映射;

PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。

FULL 会自动映射任意复杂的结果集(无论是否嵌套)。

NONE, PARTIAL, FULLPARTIAL
autoMappingUnknownColumnBehavior指定发现自动映射目标未知列(或者未知属性类型)的行为。
  • NONE: 不做任何反应
  • WARNING: 输出提醒日志 ('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior'的日志等级必须设置为 WARN)
  • FAILING: 映射失败 (抛出 SqlSessionException)
NONE, WARNING, FAILINGNONE
defaultStatementTimeout设置超时时间,它决定驱动等待数据库响应的秒数。任意正整数未设置 (null)
defaultFetchSize

为驱动的结果集获取数量(fetchSize)设置一个提示值

此参数只可以在查询设置中被覆盖。

任意正整数未设置 (null)
safeRowBoundsEnabled允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。true | falseFalse
safeResultHandlerEnabled允许在嵌套语句中使用分页(ResultHandler)。如果允许使用则设置为 false。true | falseTrue
mapUnderscoreToCamelCase

是否开启自动驼峰命名规则(camel case)映射

即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。

true | falseFalse
jdbcTypeForNull当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。JdbcType 常量,常用值:NULL, VARCHAR 或 OTHER。OTHER
lazyLoadTriggerMethods指定哪个对象的方法触发一次延迟加载。用逗号分隔的方法列表。equals,clone,hashCode,toString
returnInstanceForEmptyRow

当返回行的所有列都是空时,MyBatis默认返回 null。

当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集 (如集合或关联)。(新增于 3.4.2)

true | falsefalse
logPrefix指定 MyBatis 增加到日志名称的前缀。任何字符串未设置
logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING未设置
vfsImpl指定 VFS 的实现自定义 VFS 的实现的类全限定名,以逗号分隔。未设置
<settings>
  <setting name="useGeneratedKeys" value="false"/>
</settings>

 

6、类型处理器(typeHandlers)

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时

 都会用typeHandlers(类型处理器)将jdbcTpe与 JavaType 类型进行转换

你可以重写类型处理器或实现接口来自定义类型处理器

a、实现 org.apache.ibatis.type.TypeHandler 接口,

b、或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler

c、然后可以选择性地将它映射到一个 JDBC 类型

类型处理器Java 类型JDBC 类型
BooleanTypeHandlerjava.lang.Booleanboolean数据库兼容的 BOOLEAN
IntegerTypeHandlerjava.lang.Integerint数据库兼容的 NUMERIC 或 INTEGER
LongTypeHandlerjava.lang.Longlong数据库兼容的 NUMERIC 或 LONG INTEGER
FloatTypeHandlerjava.lang.Floatfloat数据库兼容的 NUMERIC 或 FLOAT
DoubleTypeHandlerjava.lang.Doubledouble数据库兼容的 NUMERIC 或 DOUBLE
StringTypeHandlerjava.lang.StringCHARVARCHAR

java

@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler<String> {}

xml

<typeHandlers>
  <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>

7、objectFactory

MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。

默认的对象工厂需要做的仅仅是实例化目标类

自定义对象工厂

a、实现ObjectFactory接口

b、继承DefaultObjectFactory类

java

public class ExampleObjectFactory extends DefaultObjectFactory {}

xml

<objectFactory type="org.mybatis.example.ExampleObjectFactory">
  <property name="someProperty" value="100"/>
</objectFactory>

8、插件(plugins)

<plugins>元素用来配置用户插件

MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用,通过插件来实现。

 







第二章——XML映射文件

 

 

元素描述
resultMap 用来描述如何从数据库结果集中来加载对象。
insert 映射插入语句
update 映射更新语句
delete 映射删除语句
select 映射查询语句

 

<?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=" ">
	<resultMap id=" " type=" ">
		<id column=" " property=" " />
		<result column=" " property=" " />
	</resultMap>
    <select id=" " parameterType=" " resultType=" ">
      
    </select> 
    <delete id=" ">
 
    </delete>  
</mapper>

 

注意:

a、首先mybaties从数据库中查到的列名或别名都有大小区分,尽管sql语言本身不区分大小写

b、由于autoMappingBehavior,mybaties在自动从数据库中查到的列名或别名映射到vo类成员时,会忽略大小写,例如:数据库中字段为STEDENGID,vo类中为studentId,并不影响select语句的映射

接下来是重点

b、但这个设置会被resultMap元素覆盖掉,如

    <resultMap id="student" type="student">
		<id column="studentid" property="studentId" />
	</resultMap>

此时由于column属性与property属性的存在,此时的select只能从studentid映射到studentId

c、以上内容属于查询到数据后的映射机制,对于其他updata、delect等功能语句不适用

1、select

属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType

将会传入这条语句的参数类的完全限定名或别名,

 MyBatis 可以通过 TypeHandler 自行推断,默认值为 unset。

resultType

执行语句后返回类型,可以是类的完全限定名或别名。

不能同时使用resultType 或 resultMap

resultMap

外部 resultMap 的命名引用。

不能同时使用 resultMap 或 resultType

resultSets

仅适用于多结果集

列出语句执行后返回的结果集,多个结果集用逗号分隔,形成结果集列表。

<select id=" " parameterType="int" resultType="User">
        select * from user 
        where id=#{id}
</select>

2、insert, update 和 delete

属性描述
id命名空间中的唯一标识符,可被用来代表这条语句。
parameterType

将会传入这条语句的参数类的完全限定名或别名。

 MyBatis 可以通过 TypeHandler 自行推断,默认值为 unset。

useGeneratedKeys

(仅对 insert 和 update 有用)

允许 JDBC 支持自动生成主键,并可将自动生成的主键返回,默认值:false

(比如:像 MySQL 和 SQL Server )。

keyProperty

(仅对 insert 和 update 有用)

设置主键对应的Java对象属性名

多个主键用逗号隔开,形成属性名称列表。

keyColumn

(仅对 insert 和 update 有用)

指定数据表中的主键,当主键列不是表中的第一列的时候需要设置。

多个主键用逗号分隔,形成属性名称列表。

<insert id="insertAuthor" useGeneratedKeys="true"
    keyProperty="id">
  insert into Author (username,password,email,bio)
  values (#{username},#{password},#{email},#{bio})
</insert>

<update id="updateAuthor">
  update Author set
    username = #{username},
    password = #{password},
    email = #{email},
    bio = #{bio}
  where id = #{id}
</update>

<delete id="deleteAuthor">
  delete from Author where id = #{id}
</delete>

注意:

区分vo类成员、数据库字段与sql的对应关系

insert into Author (username,password,email,bio)中对应vo类成员命名一致,注意大小写区分

values (#{username},#{password},#{email},#{bio})中对应数据库字段,注意大小写区分






第三章——MyBaties的单表关联映射(Result Map

作用:对于复杂的语句通过配置结果映射,描述它们的关系。

  • Result Map的元素
元素描述
constructor 类在实例化时,用来注入结果到构造方法中
id 用于表示那个列是主键
result 注入到字段或 JavaBean 属性的普通结果
association用于一对一关联
collection 用于一对多关联
discriminator使用结果值来决定使用哪个结果映射

 

  • ResultMap 元素的属性
属性描述
id唯一标识名
type类的完全限定名, 或者一个类型别名
autoMapping开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset)。
  • Id 和Result元素的属性
属性描述
property映射到列结果的字段或属性,如vo类数据模型。
column

从数据库中查到的列名,或者是列名的重命名标签。

这和传递给 resultSet.getString(columnName) 方法的参数一样。

javaType

一个 Java 类的完全限定名,或一个类型别名

如果你映射到一个 JavaBean,MyBatis 通常可以推断类型。

如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与期望的相一致。

 

通常的单表映射语句

MyBatis 会在幕后自动创建一个 ResultMap,再基于属性名来映射列到 JavaBean 的属性上。

如果属性和列名一致会自动匹配

如果列名和属性名不一致,可以在 SELECT 语句中对列使用别名来进行匹配

<!-- mybatis-config.xml 中 -->
<typeAlias type="com.someapp.model.User" alias="User"/>

<!-- SQL 映射 XML 中 -->
<select id="selectUsers" resultType="User">
  select id, 
    user_name           as "userName",
    hashed_password     as "hashedPassword"
  from some_table
  where id = #{id}
</select>

简单的单表关联映射

如果属性和列名一致会自动匹配

如果列名和属性名不一致,可以通过id与result元素进行匹配

​
<mapper namespace=" ">
	<resultMap id="map" type=" ">
		<id column=" " property=" " />
		<result column=" " property=" " />
	</resultMap>
    <select id="selectPerson" parameterType="int" resultType="map">
      SELECT * FROM PERSON WHERE ID = #{id}
    </select>   
</mapper>

​

 

第四章——MyBaties的多表关联映射(Result Map

1、关联的嵌套 Select 查询

属性描述
column

数据库中的列名,或者是列的别名。

 在使用复合主键时,可以使用 column="{prop1=col1,prop2=col2}" 来指定多个传递给嵌套 Select 查询语句的列名。

使 prop1 和 prop2 作为参数对象,被设置为对应嵌套 Select 语句的参数。

select

用于加载复杂类型属性的映射语句的 ID,它会从 column 属性指定的列中检索数据,作为参数传递给目标 select 语句。

 在使用复合主键时,可以使用 column="{prop1=col1,prop2=col2}" 来指定多个传递给嵌套 Select 查询语句的列名。

使 prop1 和 prop2 作为参数对象,被设置为对应嵌套 Select 语句的参数。

fetchType可选的。有效值为 lazy 和 eager。 指定属性后,将在映射中忽略全局配置参数 lazyLoadingEnabled,使用属性的值。

 

<resultMap id="blogResult" type="Blog">
  <association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>

<select id="selectBlog" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id="selectAuthor" resultType="Author">
  SELECT * FROM AUTHOR WHERE ID = #{id}
</select>

简单

在大型数据集或大型数据表上表现不佳。这个问题被称为“N+1 查询问题

N+1问题

  • 执行一个 select 查询语句来为每条记录加载详细信息(就是“N”)。
  • 执行一个  SQL 语句去对应上面的每条信息(+1)

2、关联的嵌套结果映射

属性描述
resultMap结果映射的 ID,它可以作为使用额外 select 语句的替代方案。
columnPrefix

当连接多个表时,使用列别名来避免在 ResultSet 中产生重复的列名。

通过 columnPrefix 设置列名前缀

notNullColumn

默认情况下,在至少一个被映射到属性的列不为空时,子对象才会被创建。

Mybatis 将只在这些列非空时才创建一个子对象。可以使用逗号分隔来指定多个列。

autoMapping

开启或者关闭自动映射。

这个属性会覆盖全局的属性 autoMappingBehavior。

注意,本属性对外部的结果映射无效,所以不能搭配 select 或 resultMap 元素使用

<select id="selectBlog" resultMap="blogResult">
  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
  from Blog B left outer join Author A on B.author_id = A.id
  where B.id = #{id}
</select>

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/>
</resultMap>

<resultMap id="authorResult" type="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"/>
</resultMap>

也可以写在一起

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author" 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"/>
  </association>
</resultMap>
  • columnPrefix
<collection property="brandnoticeannexes" ofType="com.hyphone.brand.entity.BrandNoticeAnnex" columnPrefix="ANNEX_">
    <id property="id" column="ID"/>
    <result property="annex" column="ANNEX"/>
    <result property="annexname" column="ANNEXNAME"/>
</collection>

<select id="getLocalNoticeById" resultMap="brandnoticeannexes">
  SELECT
    NA.ID           
    NA.ANNEX       
    NA.ANNEXNAME    
    FROM U_USER
</select >

等同于

<collection property="brandnoticeannexes" ofType="com.hyphone.brand.entity.BrandNoticeAnnex" 
    <id property="id" column="ANNEX_ID"/>
    <result property="annex" column="ANNEX_ANNEX"/>
    <result property="annexname" column="ANNEX_ANNEXNAME"/>
</collection>
<select id="getLocalNoticeById" resultMap="brandnoticeannexes">
  SELECT
    NA.ID      as      ANNEX_ID,
    NA.ANNEX     as   ANNEX_ANNEX,
    NA.ANNEXNAME   as  ANNEX_ANNEXNAME
    FROM U_USER
</select >

1、举个栗子

  • 一对一

使用<association>元素进行一对一关联映射

一个公民对应一个身份证

Person.java

        private Integer id;
	private String name;
	private Integer age;
	private String sex;
	private IdCard card;

关联嵌套的select查询

IdCardMapper.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="com.itheima.mapper.IdCardMapper">
  <!-- 根据id查询证件信息 -->
  <select id="findCodeById" parameterType="Integer" resultType="IdCard">
	  SELECT * from tb_idcard where id=#{id}
  </select>
</mapper>

PersonMapper.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="com.itheima.mapper.PersonMapper">
	<!-- 嵌套查询:通过执行另外一条SQL映射语句来返回预期的特殊类型 -->
	<select id="findPersonById" parameterType="Integer" 
                                      resultMap="IdCardWithPersonResult">
		SELECT * from tb_person where id=#{id}
	</select>
	<resultMap type="Person" id="IdCardWithPersonResult">
		<id property="id" column="id" />
		<result property="name" column="name" />
		<result property="age" column="age" />
		<result property="sex" column="sex" />
		<!-- 一对一:association使用select属性引入另外一条SQL语句 -->
		<association property="card" column="card_id" javaType="IdCard"
			select="com.itheima.mapper.IdCardMapper.findCodeById" />
	</resultMap>
</mapper>

 

关联嵌套的结果查询

<?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="com.itheima.mapper.PersonMapper">	
	<!-- 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集 -->
	<select id="findPersonById2" parameterType="Integer" 
	                                   resultMap="IdCardWithPersonResult2">
	    SELECT p.*,idcard.code
	    from tb_person p,tb_idcard idcard
	    where p.card_id=idcard.id 
	    and p.id= #{id}
	</select>
	<resultMap type="Person" id="IdCardWithPersonResult2">
	    <id property="id" column="id" />
	    <result property="name" column="name" />
	    <result property="age" column="age" />
	    <result property="sex" column="sex" />
	    <association property="card" javaType="IdCard">
	        <id property="id" column="card_id" />
	        <result property="code" column="code" />
	    </association>
	</resultMap>
	
</mapper>

 

  • 一对多

使用<collection>元素进行一对多关联映射

ofType属性与javaType属性对应,它用于指定实体对象中集合类属性所包含的元素类型

一位顾客对应对个订单

User.java

	private Integer id;                
	private String username;          
	private String address;            
	private List<Orders> ordersList;

嵌套结果查询

<?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">
<!-- namespace表示命名空间 -->
<mapper namespace="com.itheima.mapper.UserMapper">
	<!-- 一对多:查看某一用户及其关联的订单信息 
	      注意:当关联查询出的列名相同,则需要使用别名区分 -->
	<select id="findUserWithOrders" parameterType="Integer" 
						   resultMap="UserWithOrdersResult">
		SELECT u.*,o.id as orders_id,o.number 
		from tb_user u,tb_orders o 
		WHERE u.id=o.user_id 
                and u.id=#{id}
	</select>
	<resultMap type="User" id="UserWithOrdersResult">
		<id property="id" column="id"/>
		<result property="username" column="username"/>
		<result property="address" column="address"/>
		<!-- 一对多关联映射:collection 
			ofType表示属性集合中元素的类型,List<Orders>属性即Orders类 -->
		<collection property="ordersList" ofType="Orders">
			<id property="id" column="orders_id"/>
			<result property="number" column="number"/>
		</collection>
	</resultMap>
</mapper>
  • 多对多

一个商品对应多个订单,同时一个订单对应多个商品

Order.java

	private Integer id;     
	private String number; 
	private List<Product> productList;

Product.java

	private Integer id;   
	private String name;  
	private Double price; 
	private List<Orders> orders;  

select查询

ProductMapper.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="com.itheima.mapper.ProductMapper">
	<select id="findProductById" parameterType="Integer"  resultType="Product">
		SELECT * from tb_product where id IN(
		   SELECT product_id FROM tb_ordersitem  WHERE orders_id = #{id}
		)
	</select>
</mapper>

OrdersMapper.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="com.itheima.mapper.OrdersMapper">
	<!-- 多对多嵌套查询:通过执行另外一条SQL映射语句来返回预期的特殊类型 -->
	<select id="findOrdersWithPorduct" parameterType="Integer" 
              resultMap="OrdersWithProductResult">
		select * from tb_orders WHERE id=#{id}	
	</select>
	<resultMap type="Orders" id="OrdersWithProductResult">
		<id property="id" column="id" />
		<result property="number" column="number" />
		<collection property="productList" column="id" ofType="Product" 
		     select="com.itheima.mapper.ProductMapper.findProductById">
		</collection>
	</resultMap>
</mapper>

 

结果查询

<?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="com.itheima.mapper.OrdersMapper">
	<!-- 多对多嵌套结果查询:查询某订单及其关联的商品详情 -->
	<select id="findOrdersWithPorduct2" parameterType="Integer" 
	         resultMap="OrdersWithPorductResult2">
	    select o.*,p.id as pid,p.name,p.price
	    from tb_orders o,tb_product p,tb_ordersitem  oi
	    WHERE oi.orders_id=o.id 
	    and oi.product_id=p.id 
	    and o.id=#{id}
	</select>
	<!-- 自定义手动映射类型 -->
	<resultMap type="Orders" id="OrdersWithPorductResult2">
	    <id property="id" column="id" />
	    <result property="number" column="number" />
	    <!-- 多对多关联映射:collection -->
	    <collection property="productList" ofType="Product">
	        <id property="id" column="pid" />
	        <result property="name" column="name" />
	        <result property="price" column="price" />
	    </collection>
	</resultMap>	
</mapper>

 

第五章——动态 SQL

1、if

缺陷:WHERE state = ‘ACTIVE’无法实现动态

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

2、choose, when, otherwise

相当于switch

缺陷:WHERE state = ‘ACTIVE’无法实现动态

<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>

3、set

缺陷:如果最后一个if中的语句没有正确匹配会产生多余的逗号

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

4、 where

优点:where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除

在功能上等同于

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>
注意AND 后面的空格不可以省略
where
		<trim prefix="" suffixOverrides="AND">
			<if test="oprojectid != null"> projectId = #{projectid} AND </if>
			<if test="oplanitemid != null"> planitemId = #{planitemid} AND </if>
		</trim>

 

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

5、trim

  • trim:

只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入

  • prefix:

表示在trim标签内sql语句加上前缀xxx

  • suffix:

表示在trim标签内sql语句加上后缀xxx

  • suffixOverrides:

若语句的结尾是该后缀则除去

  • prefixOverrides:

若语句的开头是该后缀则除去

<update id="update" parameterType="com.cib.syzcd.trans.vo.SyzcdDksqbbbVO">
		update syzcd_dksqbbb
		<trim prefix="SET" suffixOverrides=",">
			<if test="bbid != null"> bbId = #{bbid},</if>
			<if test="cnname != null"> cnname = #{cnname},</if>
		</trim>
		where bbId = #{bbid}
</update>
<select id="getSyzcdGyshmdxxbVOByOId" parameterType="com.cib.syzcd.trans.vo.SyzcdGyshmdxxbVO" resultMap="syzcdGyshmdxxbMap">
		select * from syzcd_gyshmdxxb where
		<trim prefix="" suffixOverrides="AND">
			<if test="osupplierid != null"> supplierId = #{osupplierid} AND </if>
		</trim>
	</select>

6、foreach

  • ndex

当前迭代的次数

  • item

本次迭代获取的元素

delete

<delete id="deleteBatch" parameterType="java.util.List">
    delete from test
    where (PRSNLID, ENTID) in
    <foreach item="item" index="index" collection="list" separator="," open="(" close=")">
       #{item.prsnlid},#{item.entid}
    </foreach>
</delete>

insert

<insert id="batchSaveUser">
        insert into t_user (user_name,sex) values
        <foreach collection="users" item="u" separator=",">
            (#{u.userName},#{u.sex})
        </foreach>
</insert>

7、bind

bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文

通常用于模糊查询字符串拼接(like)

<select id="selectBlogsLike" resultType="Blog" parameterType="Blog">
  <bind name="pattern" value="'%' + title + '%'" />
  SELECT * FROM BLOG
  WHERE title LIKE #{pattern}
</select>

 

 

 

 

 

 

 

 

 

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值