Mybatis框架从入门到放弃


一、Mybatis是什么?

用于java程序和数据库连接的 半自动、轻量级 的框架。

下载地址:(整片文章基于Mybatis3.4.1)
https://Github.com/mybatis/mybatis-3/

Mybatis官方介绍文档(中文版)
https://mybatis.org/mybatis-3/zh/index.html

二、使用步骤

1.导入jar包

	将jar包复制到src的lib(一般来说是没有这个文件夹的,需要自己新建)文件夹下,然后导入jar包

一个是Mybatis的jar包,一个是Mysql驱动

2.建立数据库和表

2.1 创建一个数据库名字为mybatis(可以不同但最好相同)
在这里插入图片描述
2.2 建立tbl_employee表,并在表中填入一条数据

在这里插入图片描述

在这里插入图片描述

3.新建包和类

在这里插入图片描述

									如上建包即可

4.新建与数据库表对应的类

	因为是员工表所以我的类名字为Employee
public class Employee {
    private Integer id;
    private String lastName;//这里的属性名和表中的列名不一样 
    private String email;
    private String gender;

    public Employee() {
    }

    public Employee(String lastName, String email, String gender) {
        this.lastName = lastName;
        this.email = email;
        this.gender = gender;
    }


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", lastName='" + lastName + '\'' +
                ", email='" + email + '\'' +
                ", gender='" + gender + '\'' +
                '}';
    }

}

5.全局配置文件

根据官方文档的介绍全局配置文档的代码如下(在src下新建一个mybatis.xml文件) 下面的中文请改成自己的配置

全局配置文件的作用:获取数据库连接,<mapper>里面的地址先忽略,不需要进行更改
<?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="com.mysql.jdbc.Driver"/> 
        <property name="url" value="jdbc:mysql://localhost:数据库端口号/数据库名"/>
        <property name="username" value="数据库的用户名"/>
        <property name="password" value="数据库的密码"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

6.新建SqlSessionFactory

按照文档所描述的,

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

所以我们先建立一个。

String resource = "全局配置文件的路径";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

那么在我们知道如何建立SqlSessionFactory后,我们出现了1个问题
这段代码该写在哪里

在我们刚刚建的test包下新建一个test类

将代码写在里面,这里面的 .getResourceAsStream方法会有异常,选择throws或者try/catch都可以
在这里插入图片描述

7.获取SqlSession实例

该获取SqlSession实例了

SqlSession sqlSession = sqlSessionFactory.openSession();

在这里插入图片描述
我们发现SqlSession对象可以使用的方法有很多,几乎都是和数据库增删改查有关,下面我们选择.selectOne(),这个方法需要两个参数,第一个为执行sql语句的唯一标识符;第二个为执行sql要用的参数。

8.书写Sql映射文件

<?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.xxxxx.mybatis.bean.EmployeeMapper">
<!--    namesapce:名称空间(可以随便起)
        id:唯一标识
        resultType:返回值类型
        #{id}:从传递过来的参数中取出id值
-->
    <select id="selectEmp" resultType="com.xxxx.mybatis.bean.Employee">
        select id,last_name lastName,email,gender from tbl_employee where id = #{id}
    </select>
    <!--
    这里的sql语句我们给last_name起了一个别名为lastName和java类中的名字一样
    -->
</mapper>

9.获取SqlSession的返回值,输出并关闭sqlSession

	 try {
            Employee employee = sqlSession.selectOne("com.xxx.mybatis.bean.EmployeeMapper.selectEmp", 1);
            System.out.println(employee);
        } finally {
            sqlSession.close();
        }

10.面向接口式编程

我们在配置完后可以发现,我们可以随意往数据库中传递参数,这肯定是不可以的,所以我们将对我们所写的代码进行改进。

10.1 新建一个接口

public interface EmployeeMapper {

    public Employee getEmpById(Integer id);

}

10.2 更改sql映射文件的内容
1) 将namespace改为接口的全类名
2) 将id改为接口中对应方法的名字

<mapper namespace="com.xxx.mybatis.dao.EmployeeMapper">
<!--    namesapce:名称空间;  指定为接口的全类名
        id:唯一标识;  将对应的方法的方法名和id对应,保证一样
        resultType:返回值类型
        #{id}:从传递过来的参数中取出id值

        public Employee getEmpById(Integer id);
-->
    <select id="getEmpById" resultType="com.huyichuan.mybatis.bean.Employee">
        select id,last_name lastName,email,gender from tbl_employee where id = #{id}
    </select>
</mapper>

10.3 在test类中新建方法,代码如下

@Test
    public void test01(){
        SqlSession sqlSession = null;

        try {
            //1.获取sqlsessionfactory对象
            InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
            SqlSessionFactory sqlsessionfactoty = new SqlSessionFactoryBuilder().build(resourceAsStream);

            //2.获取sqlSession对象
            sqlSession = sqlsessionfactoty.openSession();

            //3.获取接口的实现类对象
            //接口和xml绑定,mybatis会为接口自动创建一个代理对象,代理对象去执行增删改查方法
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

            Employee empById = mapper.getEmpById(1);
            System.out.println(empById);

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }
    }

三、进一步强化

1.全局配置文件

<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
在我们写xml配置文件的时候,我们一定会先写着一段代码
其中 http://mybatis.org/dtd/mybatis-3-config.dtd为xml文档的dtd约束文件,下载之后xml文件就会有提示

1.1 properties

mybatis可以使用properties来引入外部properties配置文件的内容
    resource:引入类路径下的资源
    url:引入网络路径或者磁盘路径下的资源

1.2 settings

settings包含了很多重要的设置项
setting:用来设置每一个设置项
name:设置项名
value:设置项取值

mapUnderscoreToCamelCase  默认为false,可设置为true
例:数据库中的列名为last_Name 对应 lastName ,则会自动匹配

1.3 typeAliases

typeAliases:别名处理器,可以为我们的java类型起别名
别名不区分大小写,还是写全类名比较好

    <typeAlias type="com.huyichuan.mybatis.bean.Employee" alias="emp"/>
		typeAlias:为某个java类型起别名
       		 type:指定要起别名的类型全类名;
        	 什么都不写的情况下默认别名就是类名小写:employee
        	 alias:指定新的别名




	<package name="com.huyichuan.mybatis.bean"/>
	    package:可以为某个包下的所有类批量起别名
        name:指定包名(当前包以及下面所有后代包的每一个类都起一个默认别名(类名小写))

		
		批量起别名的情况下,也可以使用@Alias注解为某个类型指定新的别名
        tips:直接写在类里,例子见如下图片

在这里插入图片描述

1.4 environments

       environments:环境们,mybatis可以配置多种环境
        	default 指定使用某种环境,可以达到快速切换环境
       	 	environment:配置一个具体的环境信息;
        			必须有两个标签;id代表当前环境的唯一标识
            			1)transactionManager:事务管理器
                		2)type:事务管理器的类型JDBC(JdbcTransactionFactory)| MANAGED(ManagedTransactionFactory)
                			最终方案:Spring
                			
                			自定义事务控制管理器,实现TransactionFactory接口,type指定为全类名dataSource:数据源;
                				type:数据源类型;
                				UNPOOLED(UnpooledDataSourceFactory)、
                                POOLED(PooledDataSourceFactory)、
                                JNDI(JndiDataSourceFactory)
                                
							自定义数据源:实现DataSourceFactory接口即可,type是数据源的全类名
							最终方案:Spring

1.5 databaseIdProvider

databaseIdProvider:支持多数据厂商;
    type="DB_WENDOR":VendorDatabaseIdProvider
        作用就是得到数据库厂商的标识(驱动自带):mybatis就能根据数据库厂商标识来执行不同的sql
        MySQL、Oracle、SQL Server,xxx
    <databaseIdProvider type="DB_WENDOR">
		<!--为不同的数据库厂商起别名-->
        <property name="MySQL" value="mysql"/>
        <property name="Oracle" value="oracle"/>
        <property name="SQL Server" value="sqlserver"/>
			<!--在sql映射文件中 数据库语句中标签中有一个属性为databaseId="xxxx"
            xxxx为数据库厂商的别名,意味着在xxx数据库环境下,使用xxx语句-->
    </databaseIdProvider>

sql映射文件:

<select id="getEmpById" resultType="emp" databaseId="mysql">
        select * from tbl_employee where id = #{id}
</select>

1.6 mappers

将sql映射注册到全局配置中

			mapper:注册一个sql映射
            注册配置文件
           		resource:应用类路径下的sql映射文件
            	url:应用网络路径或者磁盘路径下的sql映射文件
            注册接口
            	class:引用(注册)接口:
                	1、有sql映射文件,映射文件名必须和接口同名,并且放在与接口统一目录下;
                	2、没有sql映射文件,所有的sql都是利用注解写在接口上;
               	
               推荐:比较重要的、复杂的Dao接口我们来写sql映射文件
                     不重要的、简单的Dao接口为了开发快速可以使用注解
        <mapper resource="com/xxx/mybatis/dao/mapper.xml"/>
        <mapper class="com.xxx.mybatis.dao.EmployeeMapperAnnotation"/>


<!--        批量注册,name里面写包名;
            映射文件和接口放在同一个包下、同包名
-->
        <package name="com.xxx.mybatis.dao"/>

在Dao接口使用注解直接写sql语句,如下图所示
在这里插入图片描述

2. 映射文件(Mybatis 真正的魅力)

2.1 对数据库的增删改查

一般来说我们对于数据库的操作无非 增、删、改、查 四种,在Mybatis中我们应该这样建立增删改查。	

2.1.1 在接口中创建所需的方法

如:按照id删除员工等

在这里插入图片描述

可以先忽略返回值类型统一用void,稍后将解释返回值类型的含义。

2.1.2 在 mapper.xml 中,创建增删改查的标签

标签里面的是sql语句 ;#{ }里面放的是Employee类里的属性

在这里插入图片描述
2.1.3 在test类里面测试

public void test03() throws IOException {


            InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            //1.获取到的SqlSession不会自动提交数据
            SqlSession sqlSession = sqlSessionFactory.openSession();

        try {
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

            //添加
//            Employee employee = new Employee(null,"jerry", "jj@qq.com", "1");
//            mapper.addEmp(employee);

            //修改
            Employee employee = new Employee(1,"jerry", "jj@qq.com", "0");
            boolean updateEmp = mapper.updateEmp(employee);
            System.out.println(updateEmp);

            //删除
//            mapper.deleteEmpById(2);


            //2.手动提交数据
            sqlSession.commit();
        }finally {
            sqlSession.close();
        }

    }
对于SqlSession来说,一定不要忘记提交数据,当然也有省事的方法

在这里插入图片描述

我们可以发现openSession有很多重载的方法,其中有一个参数是boolean类型的,选择这个方法,传入的参数为true,则可以自动提交

2.1.4 返回值

下面我们来讨论返回值的事情,
	mybatis允许增删改直接定义以下的返回值
       Integer(直接返回影响多少行)、
       Long、
       Boolean(0行为false、大于0行为true)、
       void
  直接在接口中修改返回值并输出即可理解。

2.2 获取自增主键的值

 mysql支持自增主键,自增主键的获取,原生jdbc是利用statement.getGeneratedKeys();
 Mybatis也是利用 getGenreatedkeys() 方法获取
   useGeneratedKeys 的默认值为false,将其改为true:使用自增主键获取主键值策略
   keyProperty:指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性

在这里插入图片描述
那么没有获取自增主键和获取了自增主键有什么区别呢???

获取自增主键后:
在这里插入图片描述

如果没有设置获取自增主键呢?
在这里插入图片描述

2.3参数处理

当我们想在一个sql语句中同时传入两个参数的时候 
如:Employee getEmpByIdAndLastName(Integer id,String lastName);
这样的时候如果我们在mapper.xml中和以前一样写sql语句的时候,会有什么结果呢?

会出现如下异常:
 org.apache.ibatis.exceptions.PersistenceException:
 ### Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [0, 1, param1, param2]
 Parameter 'id' not found. Available parameters are [0, 1, param1, param2]

那我们该如何处理呢?

2.3.1 命名参数

	明确指定封装参数时map的key:@Param("id")   (在接口中的方法的参数前面使用)
	多个参数会被封装成一个map,
    	key:使用@Param注解指定的值
    	value:参数值
	#{指定的key}取出对应的参数值
Employee getEmpByIdAndLastName(@Param("id") Integer id,@Param("lastName") String lastName);

(推荐)2.3.2 POJO(简单的java对象)

如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo
#{属性名}:取出传入的pojo的属性值
意思是说当我们传入的多个参数都是我们所需要的创建的类中的属性的时候,我们可以直接传入这个对象

(推荐)2.3.3 Map

如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,我们也可以传入map
#{key}:取出map中对应的值

在这里插入图片描述
(推荐)2.3.4 TO

如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个TO(Transfer Object)数据传输对象
Page{
int index;
int size;
}

2.3.5 Tips

tips:
如果是Collection(List、Set)类型或者是数组,也会特殊处理。也是把传入的list或者数组
封装在map中。
    key:Collection(collection),如果是List还可以使用这个key(list),数组(array)

    如果遇到这种情况
    public Employee getEmpById(List<Integer> ids);
        取值:取出第一个id的中,#{list[0]}

2.3.6 参数值的获取

#{ }:可以获取map中的值或者pojo独享属性的值;
${ }:可以获取map中的值或者pojo独享属性的值;

区别:
    #{ }:是以预编译的形式,将参数设置到sql语句中;类似于PreparedStatement:防止sql注入
    ${ }:取出的值直接拼装在sql语句中:会有安全问题,类似于Statement
    大多情况下,我们取参数的值都用该使用#{ };

    原生jdbc不支持占位符的地方我们就可以使用${ }进行取值
    比如分表:按照年份分表拆分
        select * from ${year}_salary where xxx;

#{ }:更丰富的用法:

规定参数的一些规则,
javaType、jdbcType、mode(存储过程)、numericScale、
resultMap、typeHandler、jdbcTupeName、expression(未来准备支持的功能);

jdbcType通常需要被某种特定的条件下被设置;
    在我们数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理。比如Oracle(报错);
        如果在Oracle数据库下,存入一个为空的字段,则会报错,错误为
        JdbcType OTHER:无效的类型;
        因为mybatis对所有的null都映射的是原生Jdbc的OTHER类型,oracle不能正确处理

        在mapper.xml的语句中,sql语句则应该为

insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL)
values(#{id},#{lastName},#{email,jdbcType=NULL})

    由于全局配置中,jdbcTypeForNull=OTHER:(解决方法如下)
    1、#{email,jdbcType=OTHER}; 局部配置,只影响这一句
    2、jdbcTypeForNull=NULL
    全局配置---->在mybatis.xml文件里的<settings>标签下的<setting>里面设置这个问题

2.4 select

在select语句标签中的参数
1)id:唯一标识符
2)ParameterType:参数类型(可以不写这个参数)
3)ResultType:返回值参数

2.4.1 当返回值为List时

    List<Employee> getEmpsByLastNameLike(String lastName);

xml文件中的sql语句如下所示:返回值为Employee对象;
resultType:如果返回的是一个集合,要写集合重元素的类型

<!--    List<Employee> getEmpsByLastNameLike(String lastName);-->
    <select id="getEmpsByLastNameLike" resultType="com.xxx.mybatis.bean.Employee">
        select * from tbl_employee where last_name like #{lastName}
    </select>

2.4.2 当返回一条数据,并封装为Map时

//返回一条记录的map,key是列名,值是对应的值
    Map<String,Object> getEmpByIdRetuenMap(Integer id);

resultType为Employee对象
因为map在mybatis中起了别名为map,所以resultType写为map即可

<!--    Map<Integer,Employee> getEmpByLastNameLikeReturnMap(String lastName);-->
    <select id="getEmpByIdRetuenMap" resultType="map">
        select * from tbl_employee where id = #{id}
    </select>

2.4.3 返回多条数据,封装为map,map的key为对象中的属性时

使用@MapKey注解可以设定返回map的key

//    多条记录封装一个map,Map<Integer,Employee>:键是这条记录的主键,值是记录封装后的javabean
    //有时候我们想用id当我们的主键,有时候我们想用lastName当我们的主键,那我们如何判定主键是什么呢,如下所示
    @MapKey("id")
    Map<Integer,Employee> getEmpByLastNameLikeReturnMap(String lastName);

对应的xml文档中,resultTpye为Employee对象

<!--    Map<Integer,Employee> getEmpByLastNameLikeReturnMap(String lastName);-->
    <select id="getEmpByLastNameLikeReturnMap" resultType="com.xxx.mybatis.bean.Employee">
        select * from tbl_employee where last_name like #{lastName}
    </select>

2.4.4 select的属性
1.resultMap:自定义结果集映射规则
2.resultType:自动封装

<resultMap id="MySimpleEmp" type="com.huyichuan.mybatis.bean.Employee">
<!--      指定主键列的封装规则
        id定义主键会底层有优化:
        column:指定哪一列
        property:指定对应的javaBean属性
-->
        <id column="id" property="id"/>
<!--        定义普通列封装规则-->
        <result column="last_name" property="lastName"/>
<!--        其他不指定的列会自动封装,我们只要写reulstMap就把全部的映射规则都写上-->
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
</resultMap>

<select id="getEmpById"  resultMap="MySimpleEmp">
        select * from tbl_employee where id = #{id}
</select>

id标签:用于定义主键
result标签:用于定义其他值
column:数据库的列名
property:对象的属性

2.5 联合查询

当我们遇到需要在查询Employee的同时查询员工对应的部门时该如何处理

2.5.1 新建一个Department类

在这里插入图片描述
2.5.2 在Employee属性中增加一个部门属性

在这里插入图片描述
增加其get、set方法

2.5.3 在数据库中新建Deportment表,并修改Employee表

Deportment表
表名为tbl_dept,id为主键并且自增
在这里插入图片描述
Employee表
增加外键为d_id,将 d_id 和 tbl_dept表的id相连
在这里插入图片描述

2.5.4 写sql语句和resultMap

	因为联合查询无法自动封装,因为涉及到两张表,所以我们使用resultMap来自定义封装

在这里插入图片描述

2.5.5 使用association来定义单个对象的封装规则

将xml文件的resultMap使用association标签

<resultMap id="MyDifEmp2" type="com.huyichuan.mybatis.bean.Employee">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="gender" property="gender"/>
<!--        
		association可以指定联合的javaBean对象
        property="dept":指定哪个属性是联合的对象
        javaType:指定这个属性对象的类型(不能省略)
-->
        <association property="dept" javaType="com.huyichuan.mybatis.bean.Department">
            <id column="did" property="id"/>
            <result column="dept_name" property="departmentName"/>
        </association>

</resultMap>

**2.5.6 使用association进行分部查询 **

(分部查询:当我们有department这个类的时候,我们就有departmentMapper这个接口)
1.按照员工id查询员工信息
2.根据查询员工信息中的d_id值去部门表查出部门信息
3.部门设置到员工中;

1、Department的接口
在这里插入图片描述
下面我们需要在xml文件中实现接口中的方法
2、Department的xml文件(Tips:需要在全局配置文件中加入这个xml文件)
在这里插入图片描述

3、在Employee接口中新建方法

Employee getEmpByIdStep(Integer id);

4、在xml文件中写sql语句,并且使用 resultMap 属性而非 resultType 属性

<select id="getEmpByIdStep" resultMap="MyEmpByStep">
        select * from tbl_employee where id=#{id}
</select>

5、写resultMap标签

<resultMap id="MyEmpByStep" type="com.huyichuan.mybatis.bean.Employee">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
<!--        association定义关联对象的封装规则
			property:JavaBean的属性
            select:表名当前属性是调用select指定的方法查出的结果
            colum:指定将哪一列的值传给这个方法
            流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,
            并封装给property指定的属性
-->
        <association property="dept"
          select="com.huyichuan.mybatis.dao.DepartmentMapper.getDeptById"
          column="d_id">

        </association>
</resultMap>

2.5.7 延迟加载

我们每次查询Employee对象的时候,都将Department一起查询出来,
我们希望每次部门信息在我们使用的时候再去查询;在分段查询的基础之上加上两个配置。

在主配置文件上的标签下的标签下

在这里插入图片描述

2.5.8 使用Collection查询结果集

当我们遇到如下需求的时候,我们应该如何处理?
        查询部门的时候将部门对应的所有员工信息也查出来

1、在Deportment接口内创建方法

	Department getDeptByPlus(Integer id);

2、在 xml 文件中创建标签
在这里插入图片描述

3、写 resultMap 标签

在这里之所以使用而非标签是因为,这里我们需要封装的不是一个对象而是一个集合。

<collection>标签中的property属性写Department中的员工集合属性

在这里插入图片描述

2.5.9 使用association分部查询结果集

我们首先要有两个方法,
1、根据所传入的id值查询部门
2、根据部门id搜索员工

在我们完成两个方法后
我们先需要在Employee的xml文件中写如下代码
在这里插入图片描述
然后再Department的xml中写如下代码
在这里插入图片描述

我来解释一下这段代码,select标签中的sql语句是根据传过来的id,查询表中的id和name的值
上面的resultMap中的type为 自定义规则的java类型,
collection标签中的property为 指定那个属性为联合属性
							select为 指定到哪个 命名空间 . id
							column为 指定将哪一列的值传递给这个方法

2.5.10 扩展
扩展:将多列的值传递过去
将多列的值封装map传递;
column="{key1=column1,key2=column2}"
例:如上所述,我们也可以将column里的值写为map形式
Employee中的sql语句需要的key为deptId
我们就可以写成{deptId=id}

fetchType=“lazy”:表示使用延迟加载;
-lazy:延迟加载
-eager:立即加载

2.5.11 鉴别器 (了解)

	<discriminator javaType=""></discriminator>
    鉴别器:mybatis可以使用discriminator判断某列的值,
        然后根据某列的值改变封装行为
        封装Employee:
            如果查出的是女生,就把部门信息查询出来,否则不查询
            如果是男生,把last_name这一列的值赋值给email;

2.6 动态sql

动态 SQL 是 MyBatis 的强大特性之一。

动态sql我们所需要新学的标签有下面几个

if:判断
choose (when,otherwise):分支选择:带了break的swtich-case
    如果带了id就用id查,如果带了lastName就用lastname查;只会进入其中一个
trim 字符串截取(where(封装查询条件),set(封装修改条件))
foreach

if
查询员工:要求,携带了哪个字段查询条件就带上这个字段的值

 <select id="getEmpsByConditionIf" resultType="com.huyichuan.mybatis.bean.Employee">
        select * from tbl_employee
			<if test="id!=null">
                id=#{id}
            </if>
            <if test="lastName!=null and lastName!=''">
                and last_name like #{lastName}
            </if>
            <if test="email!=null and email.trim()!=''">
                and email=#{email}
            </if>
<!--         ognl会进行字符串与数字的转换判断  “0”==0-->
            <if test="gender==0 or gender==1">
                and gender=#{gender}
            </if>
   </select>
其中test属性使用OGNL来判断表达式
     OGNL表达式的使用,参照官方文档
            从参数中取值判断
            遇见特殊符号应该去写转义字符;

当我们在进行查询的时候会遇到需要拼装字符串的时候,如上面的查询语句,当我们的test为null的时候,
sql语句就为:select * from tbl_employee and last_name like #{lastName}:此sql语句为错误的,所以我们应该如何解决这一问题呢?

		<where>
            <if test="id!=null">
                id=#{id}
            </if>
            <if test="lastName!=null and lastName!=''">
                and last_name like #{lastName}
            </if>
            <if test="email!=null and email.trim()!=''">
                and email=#{email}
            </if>
            <if test="gender==0 or gender==1">
                and gender=#{gender}
            </if>
        </where>
用where标签可以来解决这个问题,当然我们也可以在 select * from tbl_employee后加1=1,来解决这个问题

当我们把and都放到后面的时候,我们可以使用来解决这个问题

<select id="getEmpsByConditionTrim" resultType="com.huyichuan.mybatis.bean.Employee">
        select * from tbl_employee
<!--    自定义字符串的截取规则-->
        <trim prefix="where" suffixOverrides="and">
            <if test="id!=null">
                id=#{id} and
            </if>
            <if test="lastName!=null and lastName!=''">
                last_name like #{lastName} and
            </if>
            <if test="email!=null and email.trim()!=''">
                email=#{email} and
            </if>
            <if test="gender==0 or gender==1">
                gender=#{gender} and
            </if>
        </trim>
    </select>

后面多出的end或者or where标签不能解决
prefix:前缀:trim标签体中是整个字符串拼串后的结果。
prefix给拼串后的整个字符串加一个前缀
prefixOverrides:前缀覆盖:去掉整个字符串前面多余的字符串
suffix:后缀:给拼串后的整个字符串加一个后缀
suffixOverrides:后缀覆盖:去掉这个字符串后面多余的字符

choose

		<where>
            <!--
                如果带了id就用id查,如果带了lastName就用lastName查;
                只会进入其中一个
             -->
            <choose>
                <when test="id!=null">
                    id=#{id}
                </when>
                <when test="lastName!=null">
                    last_name like #{lastName}
                </when>
                <when test="email!=null">
                    email=#{email}
                </when>
                <otherwise>
                    gender = 0
                </otherwise>
            </choose>
        </where>

总结

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值