mybatis之动态sql总结

1.Mybatis的动态sql介绍

如果读者你之前玩过Jdbc相关的框架,你可能就会明白sql拼接的无奈,然后拼接成变量,作为参数传入再查询等等。动态sql的出现就是为了解决这个拼接的问题。动态sql元素对于那些使用过JSTL或者XML文件处理器的人都十分熟悉的。而这同时也是Mybatis的强大功能之一。Mybatis使用了基于强大的OGNL表达式来消除了大部分元素。在我看来就是使用标签来减少sql语句的书写量。

2.都有哪些标签用于动态sql

if 、choose (when ,otherwise) 、trim(where,set)、foreach

3.详说各个标签

if标签:

if一看就大概知道是做条件判断的,如果我们不使用这个标签,我们肯定会在代码中判断如查询的元素是否为空,传入的元素是否为空,而这时我们直接使用这个标签,就减少了代码的书写。

choose标签:

对于这类标签,就是采用多个选项中找一个,就像单项选择题,但是你不会都选择,只会从中选择1个来作为条件。就有点类似于switch。。case。

trim标签:

如果使用第一个if语句的话,就会发现没有写where标签就会报错。而这类标签通常是搭配条件标签使用的。

foreach标签:

毫无疑问这个标签肯定是用于循环了,用于遍历,如果我们传入的参数是一个数组或者集合类,那么这个标签可以循环遍历。一般我们都是使用sql中的in语句时才使用。

4.动态sql实现有条件的查询

总配置文件mybatis.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>
	
	<properties resource="db.properties"></properties>
	
	<typeAliases>
		<typeAlias type="cn.spy.model.Student" alias="Student"/>
	</typeAliases>
	
	<environments default="mysql_developer">
		<!-- mysql环境信息 -->
		<environment id="mysql_developer">
			<!-- mybatis使用jdbc事务管理方式 -->
			<transactionManager type="jdbc"></transactionManager>
			<!-- mybatis使用连接池方式来获取连接 -->
			<dataSource type="pooled">
				<!-- 配置与数据库交互的四个必要属性 -->
				<property name="driver" value="${mysql.driver}"/>
				<property name="url" value="${mysql.url}"/>
				<property name="username" value="${mysql.username}"/>
				<property name="password" value="${mysql.password}"/>
			</dataSource>
		</environment>
	</environments>
	
	<mappers>
		<mapper resource="cn\spy\model\StudentMapper.xml"/>
	</mappers>
</configuration>
db.propertis:

mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/basicjdbc?characterEncoding=utf-8
mysql.username=root
mysql.password=

工具类:为了以后可以方便使用

import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;

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 MybatisUtil {
	private static ThreadLocal<SqlSession> threadLocal =new ThreadLocal<SqlSession>();
	private static SqlSessionFactory sqlSessionFactory;
	/*
	 * 加载位于src/mybatis.xml配置文件
	 * */
	static{
		try {
			Reader reader =Resources.getResourceAsReader("mybatis.xml");
			sqlSessionFactory =new SqlSessionFactoryBuilder().build(reader);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}
	//禁止外部访问
	private MybatisUtil(){}
	/*
	 * 获取SqlSession
	 * */
	public static SqlSession getSqlSession(){
		//从当前线程中获取sqlSession对象
		SqlSession sqlSession =threadLocal.get();
		if(sqlSession ==null){
			//如果sqlSessionFactory对象不为空情况下,那么获取SqlSession对象。 
			sqlSession =sqlSessionFactory.openSession();
			//将sqlSession与当前线程绑定在一起
			threadLocal.set(sqlSession);
		}
		//直接返回sqlSession对象
		return sqlSession;
	}
	
	
	/*
	 * 关闭SqlSession与当前线程分离
	 * */
	public static void closeSqlSession(){
		//从当前线程中获取sqlSession对象
		SqlSession sqlSession =threadLocal.get();
		if(sqlSession !=null){
			//关闭sqlSession对象
			sqlSession.close();
			//分开当前线程与sqlSession对象的关系,目的是让GC尽早回收
			threadLocal.remove();
		}
	}
	public static void main(String[] args) {
		Connection conn =MybatisUtil.getSqlSession().getConnection();
		System.out.println(conn !=null ?"连接成功":"连接失败");
		MybatisUtil.closeSqlSession();
	}
}
model模型:

public class Student {
	private Integer id;
	private String name;
	private double sal;
	public Student(){}
	public Student(Integer id, String name, double sal) {
		this.id = id;
		this.name = name;
		this.sal = sal;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getSal() {
		return sal;
	}
	public void setSal(double sal) {
		this.sal = sal;
	}
	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", sal=" + sal + "]";
	}
}
StudentMapper.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="studentNamespace">
	<resultMap type="Student" id="studentMap">
		<id property="id" column="id"/>
		<result property="name" column="name"/>
		<result property="sal" column="sal"/>
	</resultMap>

	<select id="findConditionalStudent" parameterType="map" resultMap="studentMap">
		select id,name,sal from students
		<where>
			<if test="pid !=null">
				and id=#{pid}
			</if>
			<if test="pname !=null">
				and name=#{pname}
			</if>
			<if test="psal !=null">
				and sal=#{psal}
			</if>
		</where>
	</select>
</mapper>

解释:可以发现上面使用了if和where标签,省去了我们在dao实现类中还得对于输入的字段进行非空判断,这样简化了我们的程序代码。

dao实现类:

public class StudentDaoImpl implements IStudentDao{
        @Override
	public List<Student> findConditionalStudent(Student student) throws Exception {
		SqlSession sqlSession =null;
		try{
			sqlSession =MybatisUtil.getSqlSession();
			Map<String,Object> map=new LinkedHashMap<String,Object>();
			map.put("pid", student.getId());
			map.put("pname", student.getName());
			map.put("psal", student.getSal());
			return sqlSession.selectList("studentNamespace.findConditionalStudent", map);
		}catch(Exception e){
			e.printStackTrace();
			throw e;
		}finally{
			MybatisUtil.closeSqlSession();
		}
	}
}

5.动态sql实现更新学生表

至于配置文件和model类都不变,主要就是修改StudentMapper中的sql语句和dao实现类来操作sql。

StudentMapper.xml:

<update id="dynamicUpdate" parameterType="map">
	update students 
	<set>
		<if test="pname !=null">
			name=#{pname},
		</if>
		<if test="psal !=null">
			sal=#{psal},
		</if>
	</set>
	where id=#{pid}
</update>
解释:可以说使用set和if标签实现了更新操作同时也做了非空判断。其实如果不使用这种标签,我们自己写的更新sql语句也与此类似。set XXX=#{xxx} ,YYY=#{yyy},只是非空判断需要在dao实现类做了。

dao实现类:

public class StudentDaoImpl implements IStudentDao{
        @Override
	public void dynamicUpdate(Integer id, String name, double sal)
			throws Exception {
		SqlSession sqlSession =null;
		try{
			sqlSession =MybatisUtil.getSqlSession();
			Map<String,Object> map=new LinkedHashMap<String,Object>();
			map.put("pid", id);
			map.put("pname", name);
			map.put("psal", sal);
			sqlSession.update("studentNamespace.dynamicUpdate", map);
			sqlSession.commit();
		}catch(Exception e){
			e.printStackTrace();
			sqlSession.rollback();
			throw e;
		}finally{
			MybatisUtil.closeSqlSession();
		}
	}

6.动态sql实现in语句批量删除记录

数组方式:

StudentMapper.xml:

<delete id="dynamicDelete">
	delete from students where id in 
	<foreach collection="array" open="(" close=")" separator="," item="arr">
		#{arr}
	</foreach>
</delete>
解释:有人会问为什么没有输入参数parameterType,由于使用了foreach的collection属性已经指定了输入参数为array,所以就没必要再写了。foreach用于迭代数组元素,open表示开始符号,close表示结束符号,separator表示元素间的分割符,item表示迭代的数组。如果我们写sql语句:delete from students where id in (1,3,4,6,7...);而开始符号就是(,结束符号就是),分割符号是,item是我们指定的迭代数组。

dao实现类:

public void dynamicDelete(Integer[] arr) throws Exception {
	SqlSession sqlSession =null;
	try{
		sqlSession =MybatisUtil.getSqlSession();
		sqlSession.delete("studentNamespace.dynamicDelete", arr);
		sqlSession.commit();
	}catch(Exception e){
		e.printStackTrace();
		sqlSession.rollback();
		throw e;
	}finally{
		MybatisUtil.closeSqlSession();
	}	
}

集合类方式:

StudentMapper.xml:

就是使用List作为输入参数,与上面的数组是类似 的,只是指定输入参数时为list。

<delete id="dynamicDeleteList">
	delete from students where id in 
	<foreach collection="list" open="(" close=")" separator="," item="ids">
		#{ids}
	</foreach>
</delete>
dao实现类:

@Override
public void dynamicDeleteList(List<Integer> ids) throws Exception {
	SqlSession sqlSession =null;
	try{
		sqlSession =MybatisUtil.getSqlSession();
		sqlSession.delete("studentNamespace.dynamicDeleteList", ids);
		sqlSession.commit();
	}catch(Exception e){
		e.printStackTrace();
		sqlSession.rollback();
		throw e;
	}finally{
		MybatisUtil.closeSqlSession();
	}	
}

结果:


7.动态sql实现插入数据

StudentMapper.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="studentNamespace">
	
	<resultMap type="Student" id="studentMap">
		<id property="id" column="id"/>
		<result property="name" column="name"/>
		<result property="sal" column="sal"/>
	</resultMap>
	<sql id="key">
		<trim suffixOverrides=",">
			<if test="id !=null">
				id,
			</if>
			<if test="name !=null">
				name,
			</if>
			<if test="sal !=null">
				sal,
			</if>
		</trim>
	</sql>

	<sql id="value">
		<trim suffixOverrides=",">
			<if test="id !=null">
				#{id},
			</if>
			<if test="name !=null">
				#{name},
			</if>
			<if test="sal !=null">
				#{sal},
			</if>
		</trim>
	</sql>
	
	<insert id="dynamicInsert" parameterType="Student">
		insert into students(<include refid="key"/>) values(<include refid="value"/>);
	</insert>
</mapper>
解释:如果我不使用动态sql语句写的话是insert into students(id,name,sal) values(#{id},#{name},#{sal});这种形式而此处使用动态sql语句就是把后面参数的传递使用动态sql实现。后面分为两组参数,一组是传入哪些字段参数,另一组是传入的字段参数值。定义了两个sql片段,形式就是<sql></sql>.

由于需要判断参数是否为空,则还需要前面提到的if标签来做判断,如果我们不设置<trim></trim>标签就提交的话,那么程序会报sql使用错误。我们会发现其实最后一个参数的结尾是不应该有逗号的,那么我们就需要去掉,可以使用标签<trim></trim>,用来将逗号去掉换成空格。使用suffixOverrides属性设置要去掉的符号,从属性名的意思也可以看出是去掉最后的参数的。而<sql>片段是通过<include>标签使用的。

dao实现类:

@Override
public void dynamicInsert(Student student) throws Exception {
	// TODO Auto-generated method stub
	SqlSession sqlSession =null;
	try{
		sqlSession =MybatisUtil.getSqlSession();
		sqlSession.insert("studentNamespace.dynamicInsert", student);
		sqlSession.commit();
	}catch(Exception e){
		e.printStackTrace();
		sqlSession.rollback();
		throw e;
	}finally{
		MybatisUtil.closeSqlSession();
	}
}
测试:

public static void main(String[] args) throws Exception {
	IStudentDao studentDao =new StudentDaoImpl();
	studentDao.dynamicInsert(new Student(14,null,3000D));
}
结果:


----------------------------------------------------






  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值