这个一个基于Mybatis的驱动框架,该框架专门用于处理自主研发的Bin SQL,以更加方便快捷的方式实现Mybatis的注解的动态SQL.该框架基于Mybatis的默认驱动XMLLanguageDriver
进行扩展的,保留着XMLLanguageDriver
的原有功能和特性。
什么是 BIN SQL
select * from user where [IS_NOT_EMPTY_name&&age: name=#{name}]
这个就是Bin SQL ,[IS_NOT_EMPTY_name&&age: name=#{name}]
这个就是Bin SQL 表达式.
-
[IS_NOT_EMPTY
表示 Bin SQL 表达式前缀 ,不同的Bin SQL 表达式前缀对应不同的业务功能。这个对个字符串取名为binKey
。 -
name&&age
表示 属性表达式,供给Bin KEY的业务功能做对应的业务处理。这里对该字符串取名为propertyExpression
。 -
name=#{name}
一般表示属性表达式有效时,返回的SQL碎片。这里对该字符串取名为resolvedSqlFrag
。
最终,经过框架的对Bin SQL处理后,可得到:
-- 如果 'name'和'age' 都不为null,且不为空字符串时,可得到select * from user where name=#{name}
.
-- 如果 'name'或者'age'为null,或者其中一个是空字符串,可以得到select * from user
Bin SQL 表达式介绍
-
[IS_NOT_EMPTY
如果propertyExpression
的属性不为null;如果属性是字符串时判断不为空字符串;如果属性为Collection对象或者数组对象不是空集合或空数组,则条件成立,返回resolvedSqlFrag
。否则返回空字符串。 该表达式支持 '&' 和 '|' 的运算。
示例:
select * from user where [IS_NOT_EMPTY_name&&age: name=#{name}]
select * from user where [IS_NOT_EMPTY_name||age: name=#{name}]
select * from user where [IS_NOT_EMPTY_name:name=#{name}]
条件成立时,可得到select * from user where name=#{name}
; 否则,得到select * from user
-
[IS_EMPTY
如果propertyExpression
的属性为null;如果属性是字符串时判断为空字符串;如果属性为Collection对象或者数组对象判断是空集合或空数组,则条件成立,返回resolvedSqlFrag
。否则返回空字符串。该表达式支持 '&' 和 '|' 的运算。
示例:
select * from user where [IS_EMPTY_name&&age: name=#{name}]
select * from user where [IS_EMPTY_name||age: name=#{name}]
select * from user where [IS_EMPTY_name:name=#{name}]
条件成立时,可得到select * from user where name=#{name}
; 否则,得到select * from user
-
{IS_NOT_NULL
如果propertyExpression
的属性不为null,则条件成立返回resolvedSqlFrag
。否则返回空字符串。该表达式支持 '&' 和 '|' 的运算。
示例:
select * from user where [IS_NOT_NULL_name&&age: name like #{name} and age = #{age}]
select * from user where [IS_NOT_NULL_name||age: name like #{name} or age = #{age}]
条件成立时,可得到select * from user where name like #{name} and age = #{age}
; 否则,得到select * from user
-
[IS_NULL
如果propertyExpression
的属性为null,则条件成立返回resolvedSqlFrag
,否则返回空字符串。该表达式支持 '&' 和 '|' 的运算。
示例:
select * from user where [IS_NULL_name||age: name like #{name} or age = #{age} ]
select * from user where [IS_NULL_name&&age: name like #{name} or age = #{age} ]
条件成立时,可得到select * from user where name like #{name} and age = #{age}
; 否则,得到select * from user
-
[IF
将propertyExpression
看作EL表达式,如果EL表达式的执行结果为ture,就返回resolvedSqlFrag
,否则返回空字符串。如果propertyExpression
是
[IS_NOT_EMPT 属性
形式的表达式,会自动转成属性名 !=null and 属性名!=''
形式的表达式。
示例:
select * from user where [IF_name!=null&&name!='': age = #{age} ]
select * from user where [IF_IS_NOT_EMPTY name: age=#{age}]
条件成立时,可得到select * from user where age = #{age}
; 否则,得到select * from user
-
[IN
这时propertyExpression
整个字符串会被看作一个属性名。对resolvedSqlFrag
进行修整。
示例:
select * from user where [IN_ids: id in (#{id},)]
条件成立时,可得到select * from user where id in (#{id1},#{id2},#{id3})
; 否则,得到select * from user
-
[CASE
这时propertyExpression
整个字符串会被看作一个属性名。resolvedSqlFrag
会被解析成 key=属性值
,value=SQL 碎片
的映射。然后取出属性名对应的值,然后在映射中找到与属性值对应的SQL碎片。相当于Java的switch
关键字用法。
示例:
select * from user where [CASE_testCase:czb@name=#{testCase},1@name='xiaoHong',3@age=90,ELSE@name=#{name}]
可得到:
-- 如果testCase为czb,可得到select * from user where name=#{testCase}
。
-- 如果testCase为1,可得到select * from user where name = 'xiaoHong'
。
-- 如果testCase为3,可得到select * from user where age=90
。
-- 如果testCase为其他值,可得到select * from user name=#{name}
。 -
[INSERT
该Bin SQL表达式是用于生成INSERT脚本的。这时propertyExpression
应该为空字符串;而resolvedSqlFrag
变成反射属性的过滤条件,格式为EL表达式@条件成立后引用的属性名
,多个条件用','隔开。生成的INSERT脚本是非常依赖命名规范的,驼峰命名的属性,会被转换成下划线形式的列名。而类名,会被当做表名(转换成下换线形式),当然可以通过@BinMappingTable
去指定表名。而不想被映射的属性,也可以使用@BinIgnoreMapping
来标记,生成时会自动忽略被该注解标记住的属性。
示例:[INSERT:age > 30@age,name != ''@name]
再看实体类:
@BinMappingTable
public class User {
private int id;
private String name;
private String deptId;
@BinIgnoreMapping
private String phone;
@BinIgnoreMapping
private String website;
private String desName;
private Integer age;
可得到
--如果age>30
成立,但name!=''
不成立,可得到INSERT INTO user ( dept_id,id,age,des_name) values ( #{deptId},#{id},#{age},#{desName})
--如果name!=''
成立,且age>30
成立,可得到INSERT INTO user ( name,dept_id,id,age,des_name) values ( #{name},#{deptId},#{id},#{age},#{desName})
--如果age>30
和name!=''
都不成立,可得到NSERT INTO user ( dept_id,id,des_name) values ( ?,?,?)
[INSERT_NOT_NULL
与[INSERT
类似,但对每个属性加上的不能为null的过滤,如果配置了resovledSqlFrag
,会使用resovledSqlFrag
对应属性的过滤条件而不使用该表达式原有的业务过滤。
示例:[INSERT_NOT_NULL:name!=''@name]
可得到:
--如果age为null
而name=''
,可得到INSERT INTO user ( dept_id,id,des_name) values ( #{deptId},#{id},#{desName})
-- 如果age为null
,而name='1'
,可得到INSERT INTO user ( name,dept_id,id,des_name) values ( #{name},#{deptId},#{id},#{desName})
[INSERT_NOT_EMPTY
与[INSERT
类似,但对每个属性加上不为null且如果是字符串类型不能为空字符串的过滤,如果配置了resovledSqlFrag
,会使用resovledSqlFrag
对应属性的过滤条件而不使用该表达式原有的业务过滤。
示例:[INSERT_NOT_EMPTY:age>30@age]
可得到:
--如果age>30
且descName=''
,可得到INSERT INTO user ( name,dept_id,id,age) values ( #{name},#{deptId},#{id},#{age})
--如果age<30
且descName=''
,可得到INSERT INTO user ( name,dept_id,id,age) values ( ?,?,?,?)
[INSERT_FOR_EACH_users]
:这个是针对MySQL的批量插入所做出来的Bin SQL 表达是,目前仅支持@BinIgnoreMapping
注解过滤,而resovledSqlFrag
的条件过滤尚未支持。该BIN SQL 表达需要设置PropertyExpression
去指定参数名。
示例:[INSERT_FOR_EACH_users:]
可得到:INSERT INTO user ( name,dept_id,id,age,des_name ) VALUES (#{name0},#{deptId0},#{id0},#{age0},#{desName0}),(#{name1},#{deptId1},#{id1},#{age1},#{desName1}),(#{name2},#{deptId2},#{id2},#{age2},#{desName2}),(#{name3},#{deptId3},#{id3},#{age3},#{desName3}),(#{name4},#{deptId4},#{id4},#{age4},#{desName4})
[UPDATE
该Bin SQL表达式是用于生成INSERT脚本的。这时propertyExpression
应该为空字符串;而resolvedSqlFrag
变成反射属性的过滤条件,格式为EL表达式@条件成立后引用的属性名
,多个条件用','隔开。生成的INSERT脚本是非常依赖命名规范的,驼峰命名的属性,会被转换成下划线形式的列名。而类名,会被当做表名(转换成下换线形式),当然可以通过@BinMappingTable
去指定表名。而不想被映射的属性,也可以使用@BinIgnoreMapping
来标记,生成时会自动忽略被该注解标记住的属性。另外修改SQL的where
条件可以通过resolvedSqlFrag
进行配置。
示例:[UPDATE:age>#{age}@where]
可得到:UPDATE user SET name = #{name},dept_id = #{deptId},id = #{id},age = #{age},des_name = #{desName} WHERE age>#{age}
[UPDATE_NOT_NULL
与[UPDATE
类似,但对每个属性加上的不能为null的过滤,如果配置了resovledSqlFrag ,会使用resovledSqlFrag对应属性的过滤条件而不使用该表达式原有的业务过滤。
示例:[UPDATE_NOT_NULL:id==1@id,id = #{id}@where ]
可得到:
-- 如果id==1
成立,可得到:UPDATE user SET name = #{name},dept_id = #{deptId},id = #{id},des_name = #{desName} WHERE id = #{id}
-- 如果id==1
不成立,可得到:UPDATE user SET name = #{name},dept_id = #{deptId},des_name = #{desName} WHERE id = #{id}
14.[UPDATE_NOT_EMPTY
与[UPDATE
类似,但对每个属性加上不为null且如果是字符串类型不能为空字符串的过滤,如果配置了resovledSqlFrag ,会使用resovledSqlFrag对应属性的过滤条件而不使用该表达式原有的业务过滤。
示例:[UPDATE_NOT_EMPTY:id==1@id,id = #{id}@where ]
可得到:
--如果id==1
成立,且desName==''
可得到:UPDATE user SET name = #{name},dept_id = #{deptId},id = #{id} WHERE id = #{id}
-- 如果id==1
不成立,而descName==‘’
可得到:UPDATE user SET name = #{name},dept_id = #{deptId} WHERE id = #{id}
示例代码:
UserMapper
package bin.common.mapper;
import bin.common.bean.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
import java.util.Map;
public interface UserMapper {
@Select("select * from user where [IS_NOT_EMPTY_name&&age: name=#{name}] ")
List selectUserListIsNotEmptyAnd(@Param("name") String name, @Param("age") String age);
@Select("select * from user where [IS_NOT_EMPTY_name||age: name=#{name}] ")
List selectUserListIsNotEmptyOr(@Param("name") String name, @Param("age") String age);
@Select("select * from user where [IS_EMPTY_name&age: name='czb'] ")
List selecUserListIsEmptyAnd(@Param("name") String name,@Param("age") Integer age);
@Select("select * from user where [IS_EMPTY_name|age: age=#{age}] ")
List selectUserListIsEmptyOr(@Param("name") String name,@Param("age") Integer age);
@Select({"select * from user where [IS_NOT_NULL_name&&age: name like #{name} and age = #{age} ]"})
List selectUserListIsNotNullAnd(@Param("name") String name,@Param("age") Integer age);
@Select({"select * from user where [IS_NOT_NULL_name||age: name like #{name} or age = #{age} ]"})
List selectUserListIsNotNullOr(@Param("name") String name,@Param("age") Integer age);
@Select({"select * from user where [IS_NULL_name||age: name like #{name} or age = #{age} ]"})
List selectUserListIsNullOr(@Param("name") String name,@Param("age") Integer age);
@Select({"select * from user where [IS_NULL_name&&age: name like #{name} or age = #{age} ]"})
List selectUserListIsNullAnd(@Param("name") String name,@Param("age") Integer age);
@Select({"select * from user where [IF_name!=null&&name!='': age = #{age} ]"})
List selectUserListTest(@Param("name") String name,@Param("age") Integer age);
@Select("select * from user where [IN_ids: id in (#{id},)]")
List selectUserListIn(@Param("ids") List ids);
@Select("select * from user where [CASE_testCase:czb@name=#{testCase},1@name='xiaoHong',3@age=90,ELSE@name=#{name}]")
List selectUserListCase(@Param("testCase") String testCase,@Param("name") String name);
@Select("select * from user where [IS_NOT_NULL_user.age: and age=#{user.age}] [IS_NOT_EMPTY_user.name: and name = #{user.name}]")
List selectUserListUser(@Param("user") User user);
@Select("select * from user where [IS_NOT_NULL_user.age&user.name: and age=#{user.age}] [IS_NOT_EMPTY_user.name: and name = #{user.name}]")
List selectUserListUserAnd(@Param("user") User user);
@Select("select * from user where [IS_NOT_NULL_user.name: and name='czb'] [IN_users: id in (#{user.id},)]")
List selectUserListUserOrIn(@Param("user") User user,@Param("users")List users);
@Select("select * from user where [CASE_user.age:90@and age = 90 ,else@and age = 1 ] [IN_users: and id in (#{user.id},)]")
List selectUserListUserCaseIn(@Param("user") User user,@Param("users")List users);
@Select("select * from user where [IN_users:id in (#{user.id},)]")
List selectUserListUserIn(@Param("users")List users);
@Select({
"select u.id,u.name,u.age,u.dept_id,u.des_name,d.name dept_name",
"from user u ",
"left join dept d on d.id=u.dept_id ",
"where ",
"[IS_NOT_EMPTY_user.name: and u.name=#{user.name}]"
})
List
MybatisBinMainTest
package bin.common;
import bin.common.bean.User;
import bin.common.config.MyBatisBinConfig;
import bin.common.mapper.UserMapper;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.*;
import java.util.stream.IntStream;
public class MybatisBinMainTest {
private UserMapper userMapper;
private SqlSession sqlSession;
@Before
public void init(){
sqlSession=MyBatisBinConfig.openSession();
userMapper = sqlSession.getMapper(UserMapper.class);
}
@After
public void close(){
sqlSession.close();
}
@Test
public void test_selectUserListCase(){
List users = userMapper.selectUserListCase("222","ZB");
System.out.println(users);
}
@Test
public void test_selectUserListIn(){
List users = userMapper.selectUserListIn(Arrays.asList("1", "2"));
System.out.println(users);
}
@Test
public void test_selectUserListIsNotEmptyAnd(){
List users = userMapper.selectUserListIsNotEmptyAnd("czb", "");
System.out.println(users);
}
@Test
public void test_selectUserListIsNotEmptyOr(){
List users = userMapper.selectUserListIsNotEmptyOr("czb", "");
System.out.println(users);
}
@Test
public void test_selecUserListIsEmptyAnd(){
List users=userMapper.selecUserListIsEmptyAnd(null,1);
System.out.println(users);
}
@Test
public void test_selectUserListIsEmptyOr(){
List users=userMapper.selectUserListIsEmptyOr("null",90);
System.out.println(users);
}
@Test
public void test_selectUserListIsNotNullAnd(){
List users = userMapper.selectUserListIsNotNullAnd("czb", 10);
System.out.println(users);
}
@Test
public void test_selectUserListIsNotNullOr(){
List users = userMapper.selectUserListIsNotNullOr("czb", null);
System.out.println(users);
}
@Test
public void test_selectUserListIsNullOr(){
List users = userMapper.selectUserListIsNullOr("czb", null);
System.out.println(users);
}
@Test
public void test_selectUserListIsNullAnd(){
List users=userMapper.selectUserListIsNullAnd(null,null);
System.out.println(users);
}
@Test
public void test_selectUserListTest(){
List users = userMapper.selectUserListTest("czb", 90);
System.out.println(users);
}
@Test
public void test_selectUserListUser(){
User user=new User();
user.setName("czb");
user.setAge(10);
List users = userMapper.selectUserListUser(user);
System.out.println(users);
}
@Test
public void test_selectUserListUserAnd(){
User user=new User();
// user.setName("czb");
// user.setAge(10);
List users = userMapper.selectUserListUserAnd(user);
System.out.println(users);
}
@Test
public void test_selectUserListUserOrIn(){
List users=new ArrayList<>(5);
IntStream.range(0,5).forEach(i->{
User user=new User();
user.setId(i);
users.add(user);
});
List userList=userMapper.selectUserListUserOrIn(null,users);
System.out.println(userList);
}
@Test
public void test_selectUserListUserIn(){
List users=new ArrayList<>(5);
IntStream.range(0,5).forEach(i->{
User user=new User();
user.setId(i);
users.add(user);
});
List userList=userMapper.selectUserListUserIn(users);
System.out.println(userList);
}
@Test
public void test_selectUserListUserCaseIn(){
List users=new ArrayList<>(5);
IntStream.range(0,5).forEach(i->{
User user=new User();
user.setId(i);
users.add(user);
});
User user=new User();
user.setAge(2);
List userList=userMapper.selectUserListUserCaseIn(user,users);
System.out.println(userList);
}
@Test
public void test_selectUserListLeftJoin(){
User user=new User();
user.setName("czb");
List
注意事项
- 目前框架暂时不支持嵌套形式的Bin SQL。
- 除了
INSERT
和UPDATE
的相关BIN SQL 表达式不支持放在任何SQL脚本意味,其他BIN SQL表达式都可适用于任何的SQL脚本中。 - 该框架兼容Mybatis的默认驱动
XMLLanguageDriver
的所有特性。只有SQL脚本中出现了[
的字符才会被识别成BIN SQL。
项目地址
https://github.com/bin892550156/MybatisBinDynamicScriptDriven