当前位置: 代码网 > it编程>编程语言>Java > Mybatis学习

Mybatis学习

2024年08月02日 Java 我要评论
MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。insert– 映射插入语句。update– 映射更新语句。delete– 映射删除语句。select– 映射查询语句。MyBatis 在查询和结果映射做了相当多的改进。

一、mybatis简介

mybatis 是一个流行的 java 持久层框架,它提供了一个简单但强大的 sql 映射器,允许开发者将 sql 语句与 java 对象进行映射。mybatis 封装了 jdbc 的操作,简化了数据库操作的复杂性,使得开发者可以更专注于业务逻辑。

二、mybatis基本使用

快速入门(基本流程)

  1. 导入相关依赖:mybatis依赖、mysql驱动
  2. 准备mapper接口、mapper.xml配置文件
  3. 准备mybatis配置文件
  4. test中使用mybatis框架,需要先加载框架的配置文件:mybatis的配置文件,获得读取的输入流
  5. 基于输入流创建sqlsessionfactorybuilder对象(创建一个工厂对象,用于生产出sqlsession对象,一个sqlsession相当于一个会话)
  6. 由会话对象(sqlsession),基于employeemapper接口的class对象获取mapper接口类型的对象(动态代理技术)【获得代理对象】
  7. 由代理对象,调用代理类方法,从而触发sql语句。

简单说明:

  1. mybatis依赖中可能会有ibatis的东西,知道就好

  2. 为什么要mapper接口?它是用来干什么的?

    **ibatis:**之前ibatis框架的实现过程和上面大体相同,细节部分暂且不说,从宏观上讲,ibatis框架并没有动态代理那一步,直接采用sqlsession进行方法的调用。但是在方法调用时候,我们发现:方法调用时,需要提供sql的全限定名namespace和id让ibatis框架找到想要调用的方法,其中参数还只能传入一个,想要传入多个参数还要把他们封装为一个对象,或者使用map,总之很麻烦。

    **mybatis:**mybatis比ibatis多了一个动态代理,目的就是为了优化这些问题,因此相当于对ibatis又进行了一次封装。在最初进行mapper.xml文件配置时规定namespace就是接口名,那么在调用时期mybatis框架就会通过代理类对象,反射自动的将namespace和方法名进行拼接,然后找到调用的方法,执行sql语句。总之,极大方便了程序员的调用。

向sql语句传参

mybatis日志输出配置

mybatis配置文件设计标签和顶层结构如下:

我们可以在mybatis的配置文件使用settings标签设置,输出运过程sql日志!

注意:这个结构是有一定顺序的!!!!

日志配置:

<!--日志配置属性logimp 属性值slf4j......-->
<settings>
  <!-- slf4j 选择slf4j输出! -->
  <setting name="logimpl" value="slf4j"/>
</settings>
<!--选择在控制台打出日志-->
<settings>
        <!--开启了mybatis的日志输出功能-->
        <setting name="logimpl" value="stdout_logging"/>
    </settings>

#{}和${}

mybatis会将sql语句中的#{}转换为问号占位符。

${}形式传参,底层mybatis做的是字符串拼接操作。

通常不会采用${}的方式传值。一个特定的适用场景是:通过java程序动态生成数据库表,表名部分需要java程序通过参数传入;而jdbc对于表名部分是不能使用问号占位符的,此时只能使用

结论:实际开发中,能用#{}实现的,肯定不用${}。

特殊情况: 动态的不是值,是列名或者关键字,需要使用${}拼接

注解方式:

//注解方式传入参数!!
@select("select * from user where ${column} = #{value}")
user findbycolumn(@param("column") string column, 
                                @param("value") string value);

数据输入

这里数据输入具体是指上层方法(例如service方法)调用mapper接口时,数据传入的形式。

简单类型:只包含一个值的数据类型

  • 基本数据类型:int、byte、short、double、……
  • 基本数据类型的包装类型:integer、character、double、……
  • 字符串类型:string

复杂类型:包含多个值的数据类型

  • 实体类类型:employee、department、……
  • 集合类型:list、set、map、……
  • 数组类型:int[]、string[]、……
  • 复合类型:list、实体类中包含集合……

下面就讨论各种数据类型怎么传入,其实就是在mapper.xml中key怎么写?

单个简单类型参数

mapper接口中抽象方法的声明

employee selectemployee(integer empid);

sql语句

<select id="selectemployee" resulttype="com.atguigu.mybatis.entity.employee">
  select emp_id empid,emp_name empname,emp_salary empsalary from t_emp where emp_id=#{empid}
</select>

多个简单类型参数

不可以随便写,形参名称获取也不行;到底怎么写?
       方案一:注解指定【推荐】    @param直接在mapper接口里给方法中的每个参数“取别名”    然后直接就可以作为key
       方案二:mybatis默认机制     形参列表直接从左往右(arg0,arg1,arg2...)
//注解方式
int updateemployee(@param("empid") integer empid,@param("empsalary") double empsalary);
<update id="updateemployee">
  update t_emp set emp_salary=#{empsalary} where emp_id=#{empid}
</update>

实体类参数

key就等于实体对象的属性名(驼峰命名形式)【必须的!!!】

原理:mybatis会根据#{}中传入的数据,加工成getxxx()方法,通过反射在实体类对象中调用这个方法,从而获取到对应的数据。填充到#{}解析后的问号占位符这个位置。

map类型参数

传入map如何指定key值,key就是map的key

数据输出

数据无非有两种输出结果:

  1. dml语句的受影响行行数:直接使用 int 或 long 类型接收即可

  2. 查询操作返回的结果集

我们需要的是指定查询输出的数据类型即可

并且插入场景下,实现主键回显示(就是可以获得主键,再利用)

实际上,下面讨论的就是**resulttype(或者resultmap)**怎么写?

返回单个简单类型

resulttype可以返回的形式:全限定符 || 别名 || 集合类型,写泛型

全限定符:全限定符包括 :包名 + 类名 ,比如:java.lang.string是一个全限定符,指向的就是string类

集合类型:list,那么直接写student就好了

别名:有三种方法:

  1. 在mybatis配置文件中用typealiases标签和typealiase标签,并直接指定别名要起名的类
  2. 在mybatis配置文件中用typealiases标签和typealiase标签,并指定一个包名,mybatis 会在包名下面搜索需要的 java bean,怎么找?它会在包下检索每个类的

首字母小写的名字(简单的说就是找类的首字母小写,因为一般类的名字都是大写 )

  1. 直接使用注解,@alias(“别名”)

补充:mybatis有内置的类型别名,如下

下面是mybatis为常见的 java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。

别名映射的类型
_bytebyte
_char (since 3.5.10)char
_character (since 3.5.10)char
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringstring
bytebyte
char (since 3.5.10)character
character (since 3.5.10)character
longlong
shortshort
intinteger
integerinteger
doubledouble
floatfloat
booleanboolean
datedate
decimalbigdecimal
bigdecimalbigdecimal
bigintegerbiginteger
objectobject
object[]object[]
mapmap
hashmaphashmap
listlist
arraylistarraylist
collectioncollection

返回实体类对象

resulttype属性:指定封装查询结果的java实体类的全类名

<!-- 编写具体的sql语句,使用id属性唯一的标记一条sql语句 -->
<!-- resulttype属性:指定封装查询结果的java实体类的全类名 -->
<select id="selectemployee" resulttype="com.atguigu.mybatis.entity.employee">

  <!-- mybatis负责把sql语句中的#{}部分替换成“?”占位符 -->
  <!-- 给每一个字段设置一个别名,让别名和java实体类中属性名一致 -->
  select emp_id empid,emp_name empname,emp_salary empsalary from t_emp where emp_id=#{maomi}

</select>

**注意:**通过给数据库表字段加别名,让查询结果的每一列都和java实体类中属性对应起来。

增加全局配置自动识别对应关系

在 mybatis 全局配置文件中,做了下面的配置,select语句中可以不给字段设置别名

<!-- 在全局范围内对mybatis进行配置 -->
<settings>

  <!-- 具体配置 -->
  <!-- 从org.apache.ibatis.session.configuration类中可以查看能使用的配置项 -->
  <!-- 将mapunderscoretocamelcase属性配置为true,表示开启自动映射驼峰式命名规则 -->
  <!-- 规则要求数据库表字段命名方式:单词_单词 -->
  <!-- 规则要求java实体类属性名命名方式:首字母小写的驼峰式命名 -->
  <setting name="mapunderscoretocamelcase" value="true"/>

</settings>

返回map类型

适用于sql查询返回的各个字段综合起来并不和任何一个现有的实体类对应,没法封装到实体类对象中。能够封装成实体类类型的,就不使用map类型。所以我们需要学习map类型

返回的类型无法对应我们现有的实体类,因此我们返回map集合,怎么表示返回的是一个map集合呢?

两步骤:

  1. 定义映射关系,使用resultmap标签
<resultmap id="blogresultmap" type="java.util.hashmap">
  <!-- 配置列名和map中的键的映射 -->
  <result property="id" column="blog_id" />
  <result property="title" column="title" />
  <!-- 其他字段映射 -->
</resultmap>

id:id可以随便起,但是一般建议具有实际意义或者直接和map集合名对应
type:用于指定返回的map的具体类型
property:指定map的key,列名就是数据库中的字段名
<!--将数据库列名映射到map的key,这样在处理查询结果时,可以通过这些key来获取数据。-->
  1. 在查询语句中,引用resultmap映射的id
<!-- map<string,object> selectempnameandmaxsalary(); -->
<!-- 返回工资最高的员工的姓名和他的工资 -->
<select id="selectempnameandmaxsalary" resulttype="map">
  select
    emp_name 员工姓名,
    emp_salary 员工工资,
    (select avg(emp_salary) from t_emp) 部门平均工资
  from t_emp where emp_salary=(
    select max(emp_salary) from t_emp
  )
</select>

id:方法名
resulttype:返回类型,就是刚才的map的id

返回list类型

查询结果返回多个实体类对象,希望把多个实体类对象放在list集合中返回。此时不需要任何特殊处理,在resulttype属性中还是设置实体类类型即可。

<!-- list<employee> selectall(); -->
<select id="selectall" resulttype="com.atguigu.mybatis.entity.employee">
  select emp_id empid,emp_name empname,emp_salary empsalary
  from t_emp
</select>

后面可以通过起别名的方式,简写那个实体类类型,一般就是批量处理包,默认就是类名的先后字母小写,然后就可以直接写为employee

返回主键值

  1. 自增长类型主键

    mapper接口中的抽象方法

int insertemployee(employee employee);
sql语句
<!-- int insertemployee(employee employee); -->
<!-- usegeneratedkeys属性字面意思就是“使用生成的主键” -->
<!-- keyproperty属性可以指定实体类的某一属性名作为主键值,mybatis会将拿到的主键值存入这个属性 -->
<insert id="insertemployee" usegeneratedkeys="true" keyproperty="empid">
  insert into t_emp(emp_name,emp_salary)
  values(#{empname},#{empsalary})
</insert>
junit测试
@test
public void testsaveemp() {
  employeemapper employeemapper = session.getmapper(employeemapper.class);
  employee employee = new employee();
  employee.setempname("john");
  employee.setempsalary(666.66);
  employeemapper.insertemployee(employee);
  log.info("employee.getempid() = " + employee.getempid());
}
注意

mybatis是将自增主键的值设置到实体类对象中,而不是以mapper接口方法返回值的形式返回。
  1. 非自增长类型主键

    而对于不支持自增型主键的数据库(例如 oracle)或者字符串类型主键,则可以使用 selectkey 子元素:selectkey 元素将会首先运行,id 会被设置,然后插入语句会被调用!

    使用 selectkey 帮助插入uuid作为字符串类型主键示例:

<insert id="insertuser" parametertype="user">
    <!--先指定id属性作为主键,由uuid生成一个值被指定为随机字符串,设置到id中-->
    <selectkey keyproperty="id" resulttype="java.lang.string"
        order="before">
        select uuid() as id
    </selectkey>
    
    insert into user (id, username, password) 
    values (
        #{id},
        #{username},
        #{password}
    )
</insert>

在上例中,我们定义了一个 `insertuser` 的插入语句来将 `user` 对象插入到 `user` 表中。我们使用 `selectkey` 来查询 uuid 并设置到 `id` 字段中。

通过 `keyproperty` 属性来指定查询到的 uuid 赋值给对象中的 `id` 属性,而 `resulttype` 属性指定了 uuid 的类型为 `java.lang.string`。

需要注意的是,我们将 `selectkey` 放在了插入语句的前面,这是因为 mysql 在 `insert` 语句中只支持一个 `select` 子句,而 `selectkey` 中查询 uuid 的语句就是一个 `select` 子句,因此我们需要将其放在前面。

最后,在将 `user` 对象插入到 `user` 表中时,我们直接使用对象中的 `id` 属性来插入主键值。

使用这种方式,我们可以方便地插入 uuid 作为字符串类型主键。当然,还有其他插入方式可以使用,如使用java代码生成uuid并在类中显式设置值等。需要根据具体应用场景和需求选择合适的插入方式。

实体类属性和数据库字段对应关系

  1. 别名对应

    将字段的别名设置成和实体类属性一致。

<!-- 编写具体的sql语句,使用id属性唯一的标记一条sql语句 -->
<!-- resulttype属性:指定封装查询结果的java实体类的全类名 -->
<select id="selectemployee" resulttype="com.atguigu.mybatis.entity.employee">

  <!-- mybatis负责把sql语句中的#{}部分替换成“?”占位符 -->
  <!-- 给每一个字段设置一个别名,让别名和java实体类中属性名一致 -->
  select emp_id empid,emp_name empname,emp_salary empsalary from t_emp where emp_id=#{maomi}

</select>
> 关于实体类属性的约定:

getxxx()方法、setxxx()方法把方法名中的get或set去掉,首字母小写。

  1. 全局配置自动识别驼峰式命名规则

    在mybatis全局配置文件加入如下配置:

<!-- 使用settings对mybatis全局进行设置 -->
<settings>

  <!-- 将xxx_xxx这样的列名自动映射到xxxxx这样驼峰式命名的属性名 -->
  <setting name="mapunderscoretocamelcase" value="true"/>

</settings>
sql语句中可以不使用别名
<!-- employee selectemployee(integer empid); -->
<select id="selectemployee" resulttype="com.atguigu.mybatis.entity.employee">

  select emp_id,emp_name,emp_salary from t_emp where emp_id=#{empid}

</select>
  1. 使用resultmap

    使用resultmap标签定义对应关系,再在后面的sql语句中引用这个对应关系

<!-- 专门声明一个resultmap设定column到property之间的对应关系 -->
<resultmap id="selectemployeebyrmresultmap" type="com.atguigu.mybatis.entity.employee">

  <!-- 使用id标签设置主键列和主键属性之间的对应关系 -->
  <!-- column属性用于指定字段名;property属性用于指定java实体类属性名 -->
  <id column="emp_id" property="empid"/>

  <!-- 使用result标签设置普通字段和java实体类属性之间的关系 -->
  <result column="emp_name" property="empname"/>

  <result column="emp_salary" property="empsalary"/>

</resultmap>

<!-- employee selectemployeebyrm(integer empid); -->
<select id="selectemployeebyrm" resultmap="selectemployeebyrmresultmap">

  select emp_id,emp_name,emp_salary from t_emp where emp_id=#{empid}

</select>

mapperxml标签总结

mybatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 xml 文件就显得相对简单。如果拿它跟具有相同功能的 jdbc 代码进行对比,你会立即发现省掉了将近 95% 的代码。mybatis 致力于减少使用成本,让用户能更专注于 sql 代码。

sql 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):

  • insert – 映射插入语句。
  • update – 映射更新语句。
  • delete – 映射删除语句。
  • select – 映射查询语句。

select标签:

mybatis 在查询和结果映射做了相当多的改进。一个简单查询的 select 元素是非常简单:

<select id="selectperson" 
resulttype="hashmap" resultmap="自定义结构"> select * from person where id = #{id} </select>

这个语句名为 selectperson,接受一个 int(或 integer)类型的参数,并返回一个 hashmap 类型的对象,其中的键是列名,值便是结果行中的对应值。

注意参数符号:#{id} ${key}

mybatis 创建一个预处理语句(preparedstatement)参数,在 jdbc 中,这样的一个参数在 sql 中会由一个“?”来标识,并被传递到一个新的预处理语句中,就像这样:

// 近似的 jdbc 代码,非 mybatis 代码...
string selectperson = "select * from person where id=?";
preparedstatement ps = conn.preparestatement(selectperson);
ps.setint(1,id);

select 元素允许你配置很多属性来配置每条语句的行为细节:

属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
resulttype期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resulttype 和 resultmap 之间只能同时使用一个。
resultmap对外部 resultmap 的命名引用。结果映射是 mybatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resulttype 和 resultmap 之间只能同时使用一个。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
statementtype可选 statement,prepared 或 callable。这会让 mybatis 分别使用 statement,preparedstatement 或 callablestatement,默认值:prepared。

insert, update 和 delete标签:

数据变更语句 insert,update 和 delete 的实现非常接近:

<insert
  id="insertauthor"
  statementtype="prepared"
  keyproperty=""
  keycolumn=""
  usegeneratedkeys=""
  timeout="20">

<update
  id="updateauthor"
  statementtype="prepared"
  timeout="20">

<delete
  id="deleteauthor"
  statementtype="prepared"
  timeout="20">
属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
statementtype可选 statement,prepared 或 callable。这会让 mybatis 分别使用 statement,preparedstatement 或 callablestatement,默认值:prepared。
usegeneratedkeys(仅适用于 insert 和 update)这会令 mybatis 使用 jdbc 的 getgeneratedkeys 方法来取出由数据库内部生成的主键(比如:像 mysql 和 sql server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
keyproperty(仅适用于 insert 和 update)指定能够唯一识别对象的属性,mybatis 会使用 getgeneratedkeys 的返回值或 insert 语句的 selectkey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性名称。
keycolumn(仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 postgresql)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。

三、mybatis多表映射

需要掌握:

多表查询语句使用

多表结果承接实体类设计

使用resultmap完成多表结果映射

多表映射概念

将多表查询结果使用resultmap标签映射到实体类对象上

下面将介绍resultmap怎么写?

对一映射

关键词:association、javatype

association标签用于声明一个对象属性

javatype = 对象属性的类型(对象的类型)

对多映射

关键词:collection、oftype

collection:集合属性标签

oftype:集合元素数据类型

property:集合属性名(集合名)

多表映射总结

多表映射优化

setting属性属性含义可选值默认值
automappingbehavior指定 mybatis 应如何自动映射列到字段或属性。 none 表示关闭自动映射;partial 只会自动映射没有定义嵌套结果映射的字段。 full 会自动映射任何复杂的结果集(无论是否嵌套)。none, partial, fullpartial

我们可以将automappingbehavior设置为full,进行多表resultmap映射的时候,可以省略符合列和属性命名映射规则(列名=属性名,或者开启驼峰映射也可以自定映射)的result标签!

修改mybati-sconfig.xml:

<!--开启resultmap自动映射 -->
<setting name="automappingbehavior" value="full"/>

修改teachermapper.xml

<resultmap id="teachermap" type="teacher">
    <id property="tid" column="t_id" />
    <!-- 开启自动映射,并且开启驼峰式支持!可以省略 result!-->
<!--        <result property="tname" column="t_name" />-->
    <collection property="students" oftype="student" >
        <id property="sid" column="s_id" />
<!--            <result property="sname" column="s_name" />-->
    </collection>
</resultmap>

多表映射简单总结

关联关系配置项关键词所在配置文件和具体位置
对一association标签/javatype属性/property属性mapper配置文件中的resultmap标签内
对多collection标签/oftype属性/property属性mapper配置文件中的resultmap标签内

四、mybatis动态语句

动态语句

什么是动态语句?为什么需要?怎么解决(怎么写动态语句)

情景:在淘宝中,我们选取商品时,总会想要筛选商品,那么此时会有很多条件供我们选择,随着选择不同,为我们呈现出来的商品就不一样。每一次条件选择对应一条sql语句查询数据库,这是怎么做到的?(毕竟我们写出来的sql语句是固定的,难道我们把所有情况都列举出来?那是不可能的。。。)

下面通过mybatis框架提供的标签,可以做到写出动态语句

if和where标签

使用动态 sql 最常见情景是根据条件包含 where / if 子句的一部分。比如:

<!-- list<employee> selectemployeebycondition(employee employee); -->
<select id="selectemployeebycondition" resulttype="employee">
    select emp_id,emp_name,emp_salary from t_emp
    <!-- where标签会自动去掉“标签体内前面多余的and/or” -->
    <where>
        <!-- 使用if标签,让我们可以有选择的加入sql语句的片段。这个sql语句片段是否要加入整个sql语句,就看if标签判断的结果是否为true -->
        <!-- 在if标签的test属性中,可以访问实体类的属性,不可以访问数据库表的字段 -->
        <if test="empname != null">
            <!-- 在if标签内部,需要访问接口的参数时还是正常写#{} -->
            or emp_name=#{empname}
        </if>
        <if test="empsalary &gt; 2000">
            or emp_salary>#{empsalary}
        </if>
        <!--
         第一种情况:所有条件都满足 where emp_name=? or emp_salary>?
         第二种情况:部分条件满足 where emp_salary>?
         第三种情况:所有条件都不满足 没有where子句
         -->
    </where>
</select>

总结:
if标签:每个条件对应一个if,test值表示具体的条件
where标签:包围整个条件判断。作用:1.自动加where。2.自动去掉where。3.自动去掉前面的or/and。保证sql语句不报错

set标签

<!-- void updateemployeedynamic(employee employee) -->
<update id="updateemployeedynamic">
    update t_emp
    <!-- set emp_name=#{empname},emp_salary=#{empsalary} -->
    <!-- 使用set标签动态管理set子句,并且动态去掉两端多余的逗号 -->
    <set>
        <if test="empname != null">
            emp_name=#{empname},
        </if>
        <if test="empsalary &lt; 3000">
            emp_salary=#{empsalary},
        </if>
    </set>
    where emp_id=#{empid}
    <!--
         第一种情况:所有条件都满足 set emp_name=?, emp_salary=?
         第二种情况:部分条件满足 set emp_salary=?
         第三种情况:所有条件都不满足 update t_emp where emp_id=?
            没有set子句的update语句会导致sql语法错误
     -->
</update>

trim标签(了解)

使用trim标签控制条件部分两端是否包含某些字符

  • prefix属性:指定要动态添加的前缀
  • suffix属性:指定要动态添加的后缀
  • prefixoverrides属性:指定要动态去掉的前缀,使用“|”分隔有可能的多个值
  • suffixoverrides属性:指定要动态去掉的后缀,使用“|”分隔有可能的多个值
<!-- list<employee> selectemployeebyconditionbytrim(employee employee) -->
<select id="selectemployeebyconditionbytrim" resulttype="com.atguigu.mybatis.entity.employee">
    select emp_id,emp_name,emp_age,emp_salary,emp_gender
    from t_emp
    
    <!-- prefix属性指定要动态添加的前缀 -->
    <!-- suffix属性指定要动态添加的后缀 -->
    <!-- prefixoverrides属性指定要动态去掉的前缀,使用“|”分隔有可能的多个值 -->
    <!-- suffixoverrides属性指定要动态去掉的后缀,使用“|”分隔有可能的多个值 -->
    <!-- 当前例子用where标签实现更简洁,但是trim标签更灵活,可以用在任何有需要的地方 -->
    <trim prefix="where" suffixoverrides="and|or">
        <if test="empname != null">
            emp_name=#{empname} and
        </if>
        <if test="empsalary &gt; 3000">
            emp_salary>#{empsalary} and
        </if>
        <if test="empage &lt;= 20">
            emp_age=#{empage} or
        </if>
        <if test="empgender=='male'">
            emp_gender=#{empgender}
        </if>
    </trim>
</select>

choose/when/otherwise

在多个分支条件中,仅执行一个。

  • 从上到下依次执行条件判断
  • 遇到的第一个满足条件的分支会被采纳
  • 被采纳分支后面的分支都将不被考虑
  • 如果所有的when分支都不满足,那么就执行otherwise分支
<!-- list<employee> selectemployeebyconditionbychoose(employee employee) -->
<select id="selectemployeebyconditionbychoose" resulttype="com.atguigu.mybatis.entity.employee">
    select emp_id,emp_name,emp_salary from t_emp
    where
    <choose>
        <when test="empname != null">emp_name=#{empname}</when>
        <when test="empsalary &lt; 3000">emp_salary &lt; 3000</when>
        <otherwise>1=1</otherwise>
    </choose>
    
    <!--
     第一种情况:第一个when满足条件 where emp_name=?
     第二种情况:第二个when满足条件 where emp_salary < 3000
     第三种情况:两个when都不满足 where 1=1 执行了otherwise
     -->
</select>
 
总结:
这个其实可以等价于 
if..return 
else-if..return 
else-if..return 
else..return

foreach标签

基本用法

用批量插入举例

<!--
    collection属性:要遍历的集合
    item属性:遍历集合的过程中能得到每一个具体对象,在item属性中设置一个名字,将来通过这个名字引用遍历出来的对象
    separator属性:指定当foreach标签的标签体重复拼接字符串时,各个标签体字符串之间的分隔符
    open属性:指定整个循环把字符串拼好后,字符串整体的前面要添加的字符串
    close属性:指定整个循环把字符串拼好后,字符串整体的后面要添加的字符串
    index属性:这里起一个名字,便于后面引用
        遍历list集合,这里能够得到list集合的索引值
        遍历map集合,这里能够得到map集合的key
 -->
<foreach collection="emplist" item="emp" separator="," open="values" index="myindex">
    <!-- 在foreach标签内部如果需要引用遍历得到的具体的一个对象,需要使用item属性声明的名称 -->
    (#{emp.empname},#{myindex},#{emp.empsalary},#{emp.empgender})
</foreach>

批量更新时需要注意

上面批量插入的例子本质上是一条sql语句,而实现批量更新则需要多条sql语句拼起来,用分号分开。也就是一次性发送多条sql语句让数据库执行。此时需要在数据库连接信息的url地址中设置:

atguigu.dev.url=jdbc:mysql:///mybatis-example?allowmultiqueries=true

对应的foreach标签如下:

<!-- int updateemployeebatch(@param("emplist") list<employee> emplist) -->
<update id="updateemployeebatch">
    <foreach collection="emplist" item="emp" separator=";">
        update t_emp set emp_name=#{emp.empname} where emp_id=#{emp.empid}
    </foreach>
</update>

关于foreach标签的collection属性

如果没有给接口中list类型的参数使用@param注解指定一个具体的名字,那么在collection属性中默认可以使用collection或list来引用这个list集合。这一点可以通过异常信息看出来:

parameter 'emplist' not found. available parameters are [arg0, collection, list]

在实际开发中,为了避免隐晦的表达造成一定的误会,建议使用@param注解明确声明变量的名称,然后在foreach标签的collection属性中按照@param注解指定的名称来引用传入的参数。

sql片段

抽取重复的sql片段

<!-- 使用sql标签抽取重复出现的sql片段 -->
<sql id="myselectsql">
    select emp_id,emp_name,emp_age,emp_salary,emp_gender from t_emp
</sql>

引用已抽取的sql片段

<!-- 使用include标签引用声明的sql片段 -->
<include refid="myselectsql"/>
(0)

相关文章:

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

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com