1.引言
动态SQL
也就是说SQL
语句不确定,我们需要根据情况产生SQL
语句,那么在什么情况下会用到动态SQL
呢?比如我们查询Student
时,传入一个student
对象,student
对象有三个属性(id,name,sal),如果我们想根据id
查询student
,那么我们的SQL语句为:select * from student where id=#{id}
,如果我想根据id
和name
字段查询,那么我们生成的SQL
语句为:select * from student where id=#{id} and name=#{name}
,很显然这两个SQL
语句是完全不同的,在MyBatis
中如果我们使用动态SQL
那么就可以用一条语句实现。
2.配置log4j
为了方便查看我们输出的SQL
语句,我们利用log4j
输出我们的SQL语句。
POM.XML
依赖jar
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
</dependencies>
- 配置log4j文件
log4j.rootLogger=debug,stdout,logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n
log4j.logger.com.ibatis=DEBUG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
3 MyBatis之动态SQL
3.1 MyBatis动态SQL之查询(通过自定义对象Student
)
- 编写我们的SQL语句
<select id="findAllByObject" parameterType="com.Student" resultMap="studentMap">
select * from student
<where>
<if test="id!=null">
and id = #{id}
</if>
<if test="name!=null">
and name = #{name}
</if>
<if test="sal!=null">
and sal = #{sal}
</if>
</where>
</select>
- 编写第一个测试类(通过
id
和name
查询)
@Test
public void testSelectByIdAndName()
{
SqlSession sqlSession = MyBatisUtil.getSqlSession();
try{
Student s=new Student();
s.setId(2);
s.setName("zlr");
sqlSession.selectList("mynamespace.findAllByObject", s);
}catch(Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally{
sqlSession.commit();
}
MyBatisUtil.closeSqlSession();
}
- 第一个测试类生成的SQL语句
- 第二个测试类(只通过
id
查询)
@Test
public void testSelectById()
{
SqlSession sqlSession = MyBatisUtil.getSqlSession();
try{
Student s=new Student();
s.setId(2);
sqlSession.selectList("mynamespace.findAllByObject", s);
}catch(Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally{
sqlSession.commit();
}
MyBatisUtil.closeSqlSession();
}
- 第二个测试类生成的SQL语句
- 代码解释
这个代码注意三点:
1.两个测试类都是调用的同一个SQL语句(mynamespace.findAll)
2.两个测试类唯一的不同是new的student对象不一样
创建的第一个对象拥有id和name属性
创建的第二个对象只拥有id属性
3.动态SQL if语句前面都有一个and,但是MyBatis框架会自动删除第一个and
3.2 MyBatis动态SQL之查询(通过Map
对象)
- 编写SQL语句
<select id="findAllByMap" parameterType="map" resultMap="studentMap">
select * from student
<where>
<if test="id!=null">
and id = #{id}
</if>
<if test="name!=null">
and name = #{name}
</if>
<if test="sal!=null">
and sal = #{sal}
</if>
</where>
</select>
- 编写测试类
@Test
public void testSelectByMap()
{
SqlSession sqlSession = MyBatisUtil.getSqlSession();
try{
Map map=new HashMap();
map.put("id", 1);
List<Student> students =sqlSession.selectList("mynamespace.findAllByMap", map);
System.out.print(students);
}catch(Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally{
sqlSession.commit();
}
MyBatisUtil.closeSqlSession();
}
- 自动生成的SQL语句
3.3 MyBatis动态SQL之更新(通过Student
对象)
- 编写SQL语句
<update id="dynaUpdate" parameterType="com.Student">
update student
<set>
<if test="name!=null">
name = #{name},
</if>
<if test="sal!=null">
sal = #{sal},
</if>
</set>
where id = #{id}
</update>
- 编写测试类
@Test
public void testUpdate()
{
SqlSession sqlSession = MyBatisUtil.getSqlSession();
try{
Student s=new Student();
s.setId(2);
s.setName("wpx");
sqlSession.update("mynamespace.dynaUpdate", s);
}catch(Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally{
sqlSession.commit();
}
MyBatisUtil.closeSqlSession();
}
- 自动生成的SQL语句
- 数据库的改变
- 代码解释
这个代码主要注意一个地方:
set语句后面都有一个逗号
mybatis会自动删除最后一个条件的逗号
3.4 MyBatis动态SQL之删除(通过List
对象)
- 编写SQL语句
<delete id="dynaDeleteList">
delete from student where id in
<foreach collection="list" open="(" close=")" separator="," item="ids">
#{ids}
</foreach>
</delete>
- 编写测试类
@Test
public void testDeleteByList()
{
SqlSession sqlSession = MyBatisUtil.getSqlSession();
try{
List<Integer> ids=new ArrayList<Integer>();
ids.add(1);
sqlSession.update("mynamespace.dynaDeleteList", ids);
}catch(Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally{
sqlSession.commit();
}
MyBatisUtil.closeSqlSession();
}
- 自动生成的SQL语句
- 代码解释
<foreach collection="list" open="(" close=")" separator="," item="ids">
#{ids}
</foreach>
collection:代表我们传入的是list类型
open:表示开始符号
close:表示结束符合
separator:分隔符
item:表示迭代的数组,属性值可以任意,但提倡与方法的数组名相同
#{ids}:表示数组中的每个元素值
3.5 MyBatis动态SQL之删除(通过Array
数据)
- 编写SQL语句
<delete id="dynaDeleteArray">
delete from student where id in
<foreach collection="array" open="(" close=")" separator="," item="ids">
#{ids}
</foreach>
</delete>
- 编写测试类
@Test
public void testDeleteByArray()
{
SqlSession sqlSession = MyBatisUtil.getSqlSession();
try{
Integer []ids=new Integer[1];
ids[0]=2;
sqlSession.update("mynamespace.dynaDeleteArray", ids);
}catch(Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally{
sqlSession.commit();
}
MyBatisUtil.closeSqlSession();
}
- 自动生成的SQL语句
3.6 MyBatis动态SQL之插入
动态SQL
的插入是最麻烦的,需要利用SQL
片段来实现,同时MyBatis
也不会自动的帮我们去掉逗号,这都需要我们自己来处理。
- 首先我们创建SQL片段
<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="dynaInsert" parameterType="com.Student">
insert into student(<include refid="key"/>) values(<include refid="value"/>)
</insert>
- 创建测试类
@Test
public void testInsert()
{
SqlSession sqlSession = MyBatisUtil.getSqlSession();
try{
Student s=new Student();
s.setId(2);
s.setName("wpx");
sqlSession.insert("mynamespace.dynaInsert", s);
}catch(Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally{
sqlSession.commit();
}
MyBatisUtil.closeSqlSession();
}
- 自动生成的SQL语句
- 代码解释
这个代码需要注意四点
1.使用<sql>定义sql片段,id属性任意,主要用于insert时的引用
2.<sql>片段中的if语句可以直接引用insert对象的属性值
3.使用<trim>去掉sql语句的最后一个逗号
4.<include refid="key"/>引用我们自定义的<sql>片段