SSM框架学习——MyBatis动态SQL

动态SQL

什么是动态SQL

动态SQL是MyBatis强大特性之一,MyBatis3采用了功能强大的基于OGNL的表达式来完成SQL。

动态SQL主要元素

常用的动态SQL主要元素如下:

如果单独对以上元素解释理解起来还是比较费力的,接下来还是以代码的形式展现。

实践

基础部分

我们还是用之前的项目top.cairbin.test4,我们把src/main/java目录下的top.cairbin.test4包中的CustomerMapper.xml文件里的<mapper namespace="top.cairbin.test4.CustomerMapper"></mapper>中间的内容全部删除,最终效果看上去应该与下面一致:

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">
<!-- namespace表示命名空间 -->
<mapper namespace="top.cairbin.test4.CustomerMapper">

</mapper>

然后把src/test/java目录下的top.cairbin.test4中的测试类MyBatisTest里面的测试方法也删除掉

java 复制代码
package top.cairbin.test4;

import java.io.InputStream;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import top.cairbin.test4.*;

public class MyBatisTest {

}

我们先来编写表与对象的映射关系,在CustomerMapper.xml<mapper>元素之间填写如下内容(注意包名与你的一致):

xml 复制代码
<!--对应的数据集-->
<resultMap id="BaseResultMap"
	type="top.cairbin.test4.Customer">
	<id column="id" jdbcType="INTEGER" property="id" />
	<result column="username" jdbcType="VARCHAR"
		property="username" />
	<result column="jobs" jdbcType="VARCHAR" property="jobs" />
	<result column="phone" jdbcType="VARCHAR" property="phone" />
</resultMap>
<sql id="Base_Column_List">
	id, username, jobs, phone
</sql>

看起来效果应该跟下面一样,不过在后文中这个文件会越写越长,由于篇幅有限,我们每次仅给出增添部分的代码,而不是每次修改都粘贴全部配置到这里来

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">
<!-- namespace表示命名空间 -->
<mapper namespace="top.cairbin.test4.CustomerMapper">
	
	<!--对应的数据集-->
	<resultMap id="BaseResultMap"
		type="top.cairbin.test4.Customer">
		<id column="id" jdbcType="INTEGER" property="id" />
		<result column="username" jdbcType="VARCHAR"
			property="username" />
		<result column="jobs" jdbcType="VARCHAR" property="jobs" />
		<result column="phone" jdbcType="VARCHAR" property="phone" />
	</resultMap>
	<sql id="Base_Column_List">
		id, username, jobs, phone
	</sql>

</mapper>

为了方便操作SqlSession,我们在src/main/javatop.cairbin.test4包下写一个工具类,名称为MyBatisHelper

java 复制代码
package top.cairbin.test4;

import java.io.Reader;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MyBatisHelper {
	private static SqlSessionFactory sqlSessionFactory = null;
	// 初始化SqlSessionFactory对象
	static {
		try {
			// 使用MyBatis提供的Resources类加载MyBatis的配置文件
			Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
			// 构建SqlSessionFactory工厂
			sqlSessionFactory = 
					new SqlSessionFactoryBuilder().build(reader);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	// 获取SqlSession对象的静态方法
	public static SqlSession getSession() {
		return sqlSessionFactory.openSession();
	}

}

你可能对static{...}这段代码有所疑惑,但是你在学习Java语言的时候应该涉及过才对,这也算一种技巧吧,即然碰到了我们就讲一下。

还记不记得static关键字的特性?被它修饰的代码不依赖于任何实例化的对象,它们的内存是固定且唯一的,并且不会被Java的垃圾回收机制回收,直至程序结束。也就是说当它们的内存一旦被确认下来,在程序需运行的过程中,所指向的内存位置都是同一地址。

当你定义一个类MyClass,类内有个public静态成员staticTest,你并不用(new MyClass()).staticTest,而是直接以MyClass.staticTest的方式去调用。因为对于每一个MyClass它所指向的staticTest都是同一个。

那么跟我们要说的static修饰的代码块有什么关系呢?想一想你每次调用方法,都要连接一次数据库,操作完后被Java的回收机制释放掉,当调用次数过多的时候对于连接方和被连接方开销都是巨大的。那么这时候你就会想,能不能让这个过程只执行一次而且不会被Java的回收机制释放呢?这时候就可以利用我们的静态代码块 了。无论你new MyBatisHelper()多少次,它只会加载一次且在整个程序运行时有效!

编写方法

回到正题,我们来编写第一个方法,插入Customer

我们在CustomerMapper.xml<mapper></mapper>标签中间,在原来的基础上追加以下内容(这句话描述的很准确了)

xml 复制代码
<insert id="insertSelective"
parameterType="top.cairbin.test4.Customer">
insert into customer
<trim prefix="(" suffix=")" suffixOverrides=",">
	<if test="id != null">
		id,
	</if>
	<if test="username != null">
		username,
	</if>
	<if test="jobs != null">
		jobs,
	</if>
	<if test="phone != null">
		phone,
	</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
	<if test="id != null">
		#{id,jdbcType=INTEGER},
	</if>
	<if test="username != null">
		#{username,jdbcType=VARCHAR},
	</if>
	<if test="jobs != null">
		#{jobs,jdbcType=VARCHAR},
	</if>
	<if test="phone != null">
		#{phone,jdbcType=VARCHAR},
	</if>
</trim>
</insert>

然后在MyBatisTest测试类里添加测试方法(这里就用到了MyBatisHelper):

java 复制代码
@Test
public void insertCustomerTest() {
	SqlSession session = MyBatisHelper.getSession();
	Customer cc = new Customer();
	cc.setUsername("cairbin");
	cc.setJobs("student");
	cc.setPhone("888888");
	int insert = session.insert("top.cairbin.test4.CustomerMapper.insertSelective", cc);
	session.commit();
	System.out.println(insert + "," + cc);
	session.close();
}

我们运行一下,看看结果

看样子是成功了。

来看看数据库里,操作还是那样,我这里仅给个结果,你可以跳过这一步,因为我们接下来要编写查询方法。

继续编写CustomerMapper.xml文件,我们这里用到了<select>标签,并且同样用<if>来对数据进行判断。这里应当提一句,看一下<select>resultMap属性,是不是正好是<resultMap>标签的id,对应的Java类也就是Customer,同样对应数据库的表customer

xml 复制代码
<select id="findCustomerByNameAndJobs"
parameterType="top.cairbin.test4.Customer" resultMap="BaseResultMap">
select * from customer where 1=1
<if test="username !=null and username !=''">
	and username like concat('%',#{username}, '%')
</if>
<if test="jobs !=null and jobs !=''">
	and jobs= #{jobs}
</if>
</select>

继续编写测试方法,结合XML,我们可知这个是测试根据usernamejobs来查询数据的。

java 复制代码
@Test
public void findCustomerByNameAndJobsTest() {
	// 通过工具类生成SqlSession对象
	SqlSession session = MyBatisHelper.getSession();
	// 创建Customer对象,封装需要组合查询的条件
	Customer customer = new Customer();
	customer.setUsername("cairbin");
	customer.setJobs("student");
	// 执行SqlSession的查询方法,返回结果集
	List<Customer> customers = session
			.selectList("top.cairbin.test4" + ".CustomerMapper.findCustomerByNameAndJobs", customer);
	// 输出查询结果信息
	for (Customer customer2 : customers) {
		// 打印输出结果
		System.out.println(customer2);
	}
	// 关闭SqlSession
	session.close();
}

大致原理已经知道了,剩下的我们就不做演示了,自己尝试去写一写吧。

这里给出完全的CustomerMapper.xmlMyBatis.java

  • CustomerMapper.xml
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">
<!-- namespace表示命名空间 -->
<mapper namespace="top.cairbin.test4.CustomerMapper">
	
	<!--对应的数据集-->
	<resultMap id="BaseResultMap"
		type="top.cairbin.test4.Customer">
		<id column="id" jdbcType="INTEGER" property="id" />
		<result column="username" jdbcType="VARCHAR"
			property="username" />
		<result column="jobs" jdbcType="VARCHAR" property="jobs" />
		<result column="phone" jdbcType="VARCHAR" property="phone" />
	</resultMap>
	<sql id="Base_Column_List">
		id, username, jobs, phone
	</sql>
	
	<select id="selectByPrimaryKey"
		parameterType="java.lang.Integer" resultMap="BaseResultMap">
		select
		<include refid="Base_Column_List" />
		from customer
		where id = #{id,jdbcType=INTEGER}
	</select>
	<delete id="deleteByPrimaryKey"
		parameterType="java.lang.Integer">
		delete from customer
		where id = #{id,jdbcType=INTEGER}
	</delete>
	<insert id="insert" parameterType="top.cairbin.test4.Customer"
		useGeneratedKeys="true" keyProperty="id">
		insert into customer (id, username, jobs,
		phone)
		values (#{id,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR},
		#{jobs,jdbcType=VARCHAR},
		#{phone,jdbcType=VARCHAR})
	</insert>
	<insert id="insertSelective"
		parameterType="top.cairbin.test4.Customer">
		insert into customer
		<trim prefix="(" suffix=")" suffixOverrides=",">
			<if test="id != null">
				id,
			</if>
			<if test="username != null">
				username,
			</if>
			<if test="jobs != null">
				jobs,
			</if>
			<if test="phone != null">
				phone,
			</if>
		</trim>
		<trim prefix="values (" suffix=")" suffixOverrides=",">
			<if test="id != null">
				#{id,jdbcType=INTEGER},
			</if>
			<if test="username != null">
				#{username,jdbcType=VARCHAR},
			</if>
			<if test="jobs != null">
				#{jobs,jdbcType=VARCHAR},
			</if>
			<if test="phone != null">
				#{phone,jdbcType=VARCHAR},
			</if>
		</trim>
	</insert>
	<update id="updateByPrimaryKeySelective"
		parameterType="top.cairbin.test4.Customer">
		update customer
		<set>
			<if test="username != null">
				username = #{username,jdbcType=VARCHAR},
			</if>
			<if test="jobs != null">
				jobs = #{jobs,jdbcType=VARCHAR},
			</if>
			<if test="phone != null">
				phone = #{phone,jdbcType=VARCHAR},
			</if>
		</set>
		where id = #{id,jdbcType=INTEGER}
	</update>
	<update id="updateByPrimaryKey"
		parameterType="top.cairbin.test4.Customer">
		update customer
		set username = #{username,jdbcType=VARCHAR},
		jobs = #{jobs,jdbcType=VARCHAR},
		phone = #{phone,jdbcType=VARCHAR}
		where id = #{id,jdbcType=INTEGER}
	</update>
	<select id="findAllCustomer"
		resultType="top.cairbin.test4.Customer">
		select * from customer where 1=1
	</select>
	<select id="findCustomerByNameAndJobs"
		parameterType="top.cairbin.test4.Customer" resultMap="BaseResultMap">
		select * from customer where 1=1
		<if test="username !=null and username !=''">
			and username like concat('%',#{username}, '%')
		</if>
		<if test="jobs !=null and jobs !=''">
			and jobs= #{jobs}
		</if>
	</select>
	<select id="findCustomerByNameOrJobs"
		parameterType="top.cairbin.test4.Customer" resultMap="BaseResultMap">
		select * from 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>
		</choose>
	</select>
	<select id="findCustomerByIds" parameterType="List"
		resultMap="BaseResultMap">
		select * from customer where id in
		<foreach item="id" index="index" collection="list" open="("
			separator="," close=")">
			#{id}
		</foreach>
	</select>
	<select id="findCustomerByName" parameterType="Integer"
		resultMap="BaseResultMap">
		<bind name="pattern_username"
			value="'%'+_parameter.getUsername()+'%'" />
		select * from customer
		where username like #{pattern_username}
	</select>

</mapper>
  • MyBatisTest.java
java 复制代码
package top.cairbin.test4;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import top.cairbin.test4.*;

public class MyBatisTest {
	@Test
	public void insertCustomerTest() {

		SqlSession session = MyBatisHelper.getSession();
		Customer cc = new Customer();
		cc.setUsername("cairbin");
		cc.setJobs("student");
		cc.setPhone("888888");
		int insert = session.insert("top.cairbin.test4.CustomerMapper.insertSelective", cc);
		session.commit();
		System.out.println(insert + "," + cc);
		session.close();
	}

	@Test
	public void findCustomerByNameAndJobsTest() {
		// 通过工具类生成SqlSession对象
		SqlSession session = MyBatisHelper.getSession();
		// 创建Customer对象,封装需要组合查询的条件
		Customer customer = new Customer();
		customer.setUsername("cairbin");
		customer.setJobs("student");
		// 执行SqlSession的查询方法,返回结果集
		List<Customer> customers = session
				.selectList("top.cairbin.test4" + ".CustomerMapper.findCustomerByNameAndJobs", customer);
		// 输出查询结果信息
		for (Customer customer2 : customers) {
			// 打印输出结果
			System.out.println(customer2);
		}
		// 关闭SqlSession
		session.close();
	}

	/**
	 * 根据客户姓名或职业查询客户信息列表
	 */
	@Test
	public void findCustomerByNameOrJobsTest() {
		// 通过工具类生成SqlSession对象
		SqlSession session = MyBatisHelper.getSession();
		// 创建Customer对象,封装需要组合查询的条件
		Customer customer = new Customer();
		customer.setUsername("cairbin");
//	    customer.setJobs("teacher");
		// 执行SqlSession的查询方法,返回结果集
		List<Customer> customers = session.selectList("top.cairbin.test4" + ".CustomerMapper.findCustomerByNameOrJobs",
				customer);
		// 输出查询结果信息
		for (Customer customer2 : customers) {
			// 打印输出结果
			System.out.println(customer2);
		}
		// 关闭SqlSession
		session.close();
	}

	/**
	 * 更新客户
	 */
	@Test
	public void updateCustomerTest() {
		// 获取SqlSession
		SqlSession sqlSession = MyBatisHelper.getSession();
		// 创建Customer对象,并向对象中添加数据
		Customer customer = new Customer();
		customer.setId(1);
		customer.setPhone("13311111234");
		// 执行SqlSession的更新方法,返回的是SQL语句影响的行数
		int rows = sqlSession.update("top.cairbin.test4" + ".CustomerMapper.updateByPrimaryKeySelective", customer);
		// 通过返回结果判断更新操作是否执行成功
		if (rows > 0) {
			System.out.println("您成功修改了" + rows + "条数据!");
		} else {
			System.out.println("执行修改操作失败!!!");
		}
		// 提交事务
		sqlSession.commit();
		// 关闭SqlSession
		sqlSession.close();
	}

	/**
	 * 根据客户编号批量查询客户信息
	 */
	@Test
	public void findCustomerByIdsTest() {
		// 获取SqlSession
		SqlSession session = MyBatisHelper.getSession();
		// 创建List集合,封装查询id
		List<Integer> ids = new ArrayList<Integer>();
		ids.add(1);
		ids.add(2);
		// 执行SqlSession的查询方法,返回结果集
		List<Customer> customers = session.selectList("top.cairbin.test4" + ".CustomerMapper.findCustomerByIds", ids);
		// 输出查询结果信息
		for (Customer customer : customers) {
			// 打印输出结果
			System.out.println(customer);
		}
		// 关闭SqlSession
		session.close();
	}

	/**
	 * bind元素的使用:根据客户名模糊查询客户信息
	 */
	@Test
	public void findCustomerByNameTest() {
		// 通过工具类生成SqlSession对象
		SqlSession session = MyBatisHelper.getSession();
		// 创建Customer对象,封装查询的条件
		Customer customer = new Customer();
		customer.setUsername("cair");
		// 执行sqlSession的查询方法,返回结果集
		List<Customer> customers = session.selectList("top.cairbin.test4" + ".CustomerMapper.findCustomerByName",
				customer);
		// 输出查询结果信息
		for (Customer customer2 : customers) {
			// 打印输出结果
			System.out.println(customer2);
		}
		// 关闭SqlSession
		session.close();
	}

}
相关推荐
数据智能老司机30 分钟前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机2 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机2 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机2 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i2 小时前
drf初步梳理
python·django
每日AI新事件2 小时前
python的异步函数
python
这里有鱼汤3 小时前
miniQMT下载历史行情数据太慢怎么办?一招提速10倍!
前端·python
databook12 小时前
Manim实现脉冲闪烁特效
后端·python·动效
程序设计实验室12 小时前
2025年了,在 Django 之外,Python Web 框架还能怎么选?
python
倔强青铜三14 小时前
苦练Python第46天:文件写入与上下文管理器
人工智能·python·面试