MyBatis学习(四)

动态SQL


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

动态SQL就是根据不同的条件拼接SQL语句


提示:以下是本篇文章正文内容,下面案例可供参考

一、动态SQL中常用元素

1. if元素

用于单条件判断
在实际开发过程中,我们可能需要通过某个条件查询某个对象的信息,就需要通过if条件判断

<select id = "findCustomerByNameAndJobs" //通过姓名和职业查询信息
		parameterType = "com.itiheima.pojo.Customer"//接收的参数类型为对象
		resultType = "com.itheima.pojo.Customer">//返回的参数也为对象
	select * from t_customer where 1=1/*为了拼接有效的条件,这里用一个永真的条件,
	这样后面是真的,就会是select * from t_costomer where 1=1 and useanme ...而不是where
	and...这样的错误语句*/
	<if test = "username != null and username != ''">//test属性是用于对username进行非空判断
		and username like concat('%',#{username},'%')//如果条件为真,这条语句就会拼接到查询语句中
	</if>
	<if test = "jobs != null and jobs != ''">
		and jobs = #{jobs}//#{jobs}是一个占位符,用于接收之后传来的对象中的属性
	</if>
</select>	

编写类方法进行测试

@Test
pubilc void findCustomerByNameAndJobsTest(){
	SqlSession session = MyBatisUtis.getSession();//引入之前建好的工具类中的方法创建SqlSession
	Customer customer = new Customer();
	customer.setUsername("Jack");//传入要查询对象的名字
	customer.setJobs("teacher");//传入想要查询对象的职业名称
	//执行SqlSession的查询方法,返回结果集
	List<Customer> customers = session.selectList("com.itheima.mapper"+".CustomerMapper.findCustomerByNameAndJobs",customer);
	/*
	这里传入的是映射文件中查询方法的全限定类名和已经赋值的costomer对象
	*/
	//输出结果集
	......
	
}

2. chose、when、otherwise元素

chose、when、otherwise联合起来相当于java语句中的switch…case…default语句,用于多条件判断,但是最终只会执行其中的一个。

<select id = "findCustomerByNameAndJobs" //通过姓名和职业查询信息
		parameterType = "com.itiheima.pojo.Customer"//接收的参数类型为对象
		resultType = "com.itheima.pojo.Customer">//返回的参数也为对象
	select * from t_customer where 1=1
	<choose>
		<when test = "username != null and username != ''">
			and username like concat('%',#{username},'%')//模糊查询
		</when>
		<when test = "jobs != null and jobs != ''">
			and jobs = #{jobs};
		</when>
		<otherwise>
			and phone is not null
		</otherwise>
</select>

上述代码中,如果第一个条件为真,则则执行第一个,后面不执行;否则判断第二个,如果真,只执行第二个;如果所有的when元素都不为真,则就会默认拼接default中的语句并执行。不管怎样,总会执行一条语句,不会所有的条件都不执行。


3. where、trim元素

(1)where元素会替换掉原来的select * from users where 1=1中的where 1=1,并且会自动将where之后的“AND(and)”或“OR(or)”去掉

<select id = "findCustomerByNameAndJobs" //通过姓名和职业查询信息
		parameterType = "com.itiheima.pojo.Customer"//接收的参数类型为对象
		resultType = "com.itheima.pojo.Customer">//返回的参数也为对象
	select * from t_customer
	<where>
		<if test = "username != null and username != ''">
			and username like concat('%',#{username},'%')
		</if>
		<if test = "jobs != null and jobs != ''">
			and jobs = #{jobs}
		</if>
	</where>
</select>

注意:只有<where>元素内的某一个或多个条件成立时,才会进行拼接并且加入关键字“where”,否则不会添加
(2)trim元素用于删除多余的关键字,可以直接实现where元素的功能。包含四个属性:prefix、prefixOverrides、suffix、suffixOverrides。

<select id = "findCustomerByNameAndJobs" //通过姓名和职业查询信息
		parameterType = "com.itiheima.pojo.Customer"//接收的参数类型为对象
		resultType = "com.itheima.pojo.Customer">//返回的参数也为对象
	select * from t_customer
	<trim prefix = "where" prefixOverrides= "and">//为SQL语句增加前缀“where”,去除指定的前缀“and”
		<if test = "username != null and username != '' ">
			and username like concat('%',#{username},'%')
		</if>
		<if test = "jobs != null and jobs != '' ">
			and jobs = #{jobs}
		</if>
	</trim>
</select>

suffix元素是指给SQL语句增加的后缀;suffixOverrides是指指定SQL语句中去掉的后缀字符串。

4.set元素

set元素用于更新操作,了、它可以在动态SQL语句前输出一个关键字SET,并将SQL语句最后一个多余逗号去掉。使用set元素与if元素相结合的方式可以更新需要更新的字段。

<update id = "updateCustomer" parameterType = "com.itheima.pojo.Customer">
	update t_customer
	<set>
		<if test = "username != null and username != '' ">
			username = #{username},
		</if>//如果传入为空则不拼接
		<if test = "jobs != null and jobs != '' ">
			jobs = #{jobs},
		</if>//传入为空则不拼接
		<if test = "telephone != null and telephone != '' ">
			telephone = #{telephone},
		</if>//传入为空则不拼接

注意:如果<set>元素内包含的内容都为空,则会出现SQL语法错误。因此使用<set>元素进行字段信息更新时,要确保传入的更新字段不能都为空。
更新除了可以使用set元素外,还可以使用trim元素。

5. foreach元素

foreach元素主要用于遍历,能够支持数组、List或Set接口的集合。通常和关键字“in”结合使用。
(1)item:表示集合中每一个元素进行迭代时的别名。该属性为必选属性。
(2)index:在List和数组中,index是元素的序号;在Map中index是元素的key。该属性为可选项。
(3)open:表示foreach语句代码开始的符号,一般和cllose=“)”合用。常用在in条件语句中。该属性为可选属性。
(4)separator:表示元素之间的分隔符。
(5)close:foreach语句代码的关闭符号。
(6)collection:必选项。若传入参数为单参数且是一个List,属性值为list,若为数组,属性值为array;若为多参数,封装成一个Map,属性值为Map。

二、总结

在这里插入图片描述
对所学知识的一个笔记!!!

(一)Mybatis的特点:

1.Mybatis是面向接口的开发,只需要写接口,不需要自己进行实现类的书写
2.实现接口通过一个一个Mapper文件进行映射,每一个接口中的方法要和Mapper文件中对应实现的sql语句的id值对应
3.namespace是实现接口的接口名,每个标签中的id是接口中的方法
4.Mybatis中事务的自动提交关闭了,所以需要自动进行提交

(二)Mybatis使用的两种方式

1.不创建接口
(1)创建Mapper.xml文件进行sql语句的统一管理
(2)增删改查语句通过SqlSession进行调用,通过mapper.xml中的id值作为方法得到参数进行对应语句的执行
(3)参数注入进行数据库的操作
参数注入使用#{}或者${}:

  • 如果调用的方法进行参数注入时,参数只有一个,{}可以写任意内容
  • 如果调用的方法进行参数注入时,参数有多个,{}中写的是map的key
  • 如果调用的方法进行参数注入时,此时注入一个对象,对象的属性默认作为map的key
    2.使用接口
    (1)mapper.xml对应接口,进行方法调用
    (2)参数注入时
  • 如果一个参数,{}参数注入进行任意书写
  • 如果多个参数,{}写map的key,key需要在接口中的方法进行@Param注解定义
  • 如果参数是一个对象,对象的属性作为key,进行参数注入
    3.要在带注解的映射器接口中使用动态SQL,可以使用script元素,例如
    要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素。比如:
 @Update({"<script>",
      "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}",
      "</script>"})
    void updateAuthorValues(Author author);

(三)作用域和生命周期

1.依赖注入框架可以创建线程安全的、基于事务的SqlSession和映射器,并将它们直接注入到bean中,因此可以直接忽略它们的生命周期。 如果对如何通过依赖注入框架使用 MyBatis 感兴趣,可以研究一下 MyBatis-Spring 或 MyBatis-Guice 两个子项目。
2.Mybatis三大对象

  • SqlSessionFactoryBuilder:这个类可以被实例化、使用和丢弃,一旦创建了SqlSessionFactory,就不再需要SqlSessionFactoryBuilder,因此它的最佳作用域是方法作用域(局部方法变量),可以重用SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好不要一直保留,以保证所有XML解析资源可以被释放到更重要的事情
  • SqlSessionFactory:一旦被创建就应该在运行的期间一直存在,没有任何理由丢弃或重新创建另一个实例;使用SqlSessionFactory最佳实践是在应用期间不要重复创建多次,多次创建被视为一种代码的“坏习惯”,最佳作用域是应用作用域,最简单就是使用单例模式或者静态单例模式
  • SqlSession:没给线程都应该有它自己的SqlSession实例,但不是线程安全的,不能被共享;因此最佳作用域是请求或方法作用域;不能将SqlSession实例的引用放在一个类的静态域甚至是一个类的实例变量,也决不能将 SqlSession 实例的引用放在任何类型的托管作用域中,如Servlet框架中的HttpSession,在web中考虑放到一个和Http请求相似的作用域;即每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,应该把这个关闭操作放到 finally 块中。

(四)Mybatis缓存

1.一级缓存:用SqlSession进行数据库中数据的查询,默认开启,一级缓存数据存在于SqlSession中
(1)一级缓存用的是同一个SqlSession,并且只有方法名,参数都相同才会使用缓存,否则还是会访问数据库
(2)map结构进行的数据存储
2.二级缓存:手动开启,而且进行结果集对应的类,进行序列化;namespace的缓存

<mapper namespace="com.neuedu.dao.UserDao">
    <cache/> 

不共用SqlSession但是相同方法,相同参数会从缓存中去取,不会再访问数据库

(五)resultMap的标签

作用:
(1)表中的列名和java中实体类属性名不一致时可以进行对应

 进行列名和属性名的对应
<resultMap id="users" type="User">
        <id column="id" property="id" />
        <result column="r_id" property="rId"/>
    </resultMap>
    <select id="gets" resultMap="users">
--         select id,username,password,email,phone,r_id from user
      select * from user
    </select>        

(2)在一对多,多对一时使用ResultMap

进行一对多的配置
public class Role {
    private Integer id;
    private String name;
//    一个角色可以对应多个用户,一对多的关系
    private List<User> users;
}

<resultMap id="roles" type="Role">
    <collection property="users" select="getById" column="id">
        <result property="rId" column="r_id"/>
    </collection>
</resultMap>
<resultMap id="users" type="User">
    <result column="r_id" property="rId"/>
</resultMap>
<select id="getAll" resultMap="roles">
    select * from role
</select>
<select id="getById" resultMap="users">
    select * from user where r_id=#{id}
</select>

@Test
public void test27(){
    SqlSession sqlSession = factory.openSession();
    RoleDao mapper = sqlSession.getMapper(RoleDao.class);
    List<Role> mapper2 = mapper.getAll();
    System.out.println(mapper2);
    sqlSession.commit();
}

进行表连接的语句书写
进行所有列的对应:
<resultMap id="roles" type="Role">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <collection property="users" javaType="list" ofType="User">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="email" column="email"/>
        <result property="password" column="password"/>
        <result property="phone" column="phone"/>
        <result property="rId" column="r_id"/>
    </collection>

</resultMap>


<select id="getAll" resultMap="roles">
    select * from role,user where role.id=user.r_id
</select>

(六)动态代理

对象的执行方法交给代理(proxy)来负责。
接口定义,进行了方法声明:
(1)方法调用,接口进行了mapper接收,调用方法,进行方法功能的实现
(2)接口的实现类对象,动态代理
举例子:
静态代理:公司常年法务–》静态代理
动态代理:个人律师–》代理完就没事了,代理关系解除
1.JDK动态代理:要求有接口

接口:
public interface Core {
    void t1();// 核心要做的一件事  打官司
}
接口实现类:
public class CoreImpl implements Core {
    @Override
    public void t1() {
        System.out.println("打官司");
    }
}

public class Test1 implements InvocationHandler//代理类 {
    private Core core;
    public Test1(Core core){
        this.core=core;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("请律师");
        method.invoke(core,args);
        System.out.println("合同接触==============");
        return null;
    }
}
public class Demo {
    public static void main(String[] args) {
        Core core = new CoreImpl();
        Test1 t1 = new Test1(core);
        Core o = (Core)Proxy.newProxyInstance(Core.class.getClassLoader(), CoreImpl.class.getInterfaces(), t1);//产生代理对象
        o.t1();

        Core c1 = new CoreImpl();
        c1.t1();
    }
}

2.CGLib动态代理
需要导包

public class CCore {父类的创建
    public void t1(){
        System.out.println("核心功能执行");
    }
}

代理逻辑
package com.test;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("前期请律师");
        methodProxy.invokeSuper(o,objects);
        System.out.println("后期进行合同解除");
        return null;
    }
}

代理实现
public class CDemo {
    public static void main(String[] args) {
        Enhancer e = new Enhancer();
        e.setSuperclass(CCore.class);
        e.setCallback(new CProxy());
        CCore o = (CCore)e.create();
        o.t1();

        CCore c = new CCore();
        c.t1();

    }
}

(七)单例模式

一个类只有一个对象,节省内存,节省对象创建和销毁占用的时间
1.饿汉模式

为静态变量进行赋值,只要类加载了,对象已经存在,不管是否使用,对象已经占用了内存
public class Cat {
    private String name;
    private static Cat cat=new Cat();  静态的全局变量
//    构造方法要私有
    private Cat(){ 构造方法私有

    }
    public static Cat getOne(){ 方法进行对象的返回
        return  cat;
    }
}

2.懒汉模式

类加载时,对象不进行创建,什么时候用,什么时候进行对象的创建
public class Cat {
    private String name;
    private static Cat cat;
//    构造方法要私有
    private Cat(){

    }
    public static Cat getOne(){
        if (cat==null){
            cat = new Cat();
        }
        return  cat;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小猿F

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值