官网地址:
项目演示使用maven工程,新建一个Maven工程,直接引用如下库
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetlsql</artifactId>
<version>${version}</version>
</dependency>
然后再引入数据库驱动,本章使用sqlserver数据库作为例子,作为快速开始,避免安装数据库服务器,你也可以使用任意其他数据库
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc4</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
BeetlSQL访问数据库不依赖数据库连接池,但有数据库连接池是大多数项目的标配。
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
最后,需要准备一个sql脚本,以初始化数据库。保存如下sql到resources/db/schema.sql
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`department_id` int(11) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ;
BEGIN;
INSERT INTO `sys_user` VALUES (1, 'lijz', 1, NULL);
INSERT INTO `sys_user` VALUES (2, 'lucy', 1, NULL);
INSERT INTO `sys_user` VALUES (3, 'bear', 2, NULL);
INSERT INTO `sys_user` VALUES (4, 'mike', 1, NULL);
INSERT INTO `sys_user` VALUES (5, 'lisan', 1, NULL);
INSERT INTO `sys_user` VALUES (6, 'xb', 1, NULL);
INSERT INTO `sys_user` VALUES (7, 'duanwu', 2, NULL);
INSERT INTO `sys_user` VALUES (8, 'fenh', 1, NULL);
INSERT INTO `sys_user` VALUES (9, 'lj', 2, NULL);
INSERT INTO `sys_user` VALUES (10, 'gshen', 1, NULL);
INSERT INTO `sys_user` VALUES (11, 'lihui', 1, NULL);
COMMIT;
创建一个Java类com.QuickTest,如下
import com.zaxxer.hikari.HikariDataSource;
import org.beetl.sql.core.*;
import org.beetl.sql.core.db.H2Style;
import org.beetl.sql.ext.DBInitHelper;
import org.beetl.sql.ext.DebugInterceptor;
import javax.sql.DataSource;
import java.util.Set;
public class QuickTest {
private static DataSource datasource() {
HikariDataSource ds = new HikariDataSource();
//内存数据库
ds.setJdbcUrl("jdbc:h2:mem:dbtest;DB_CLOSE_ON_EXIT=FALSE");
ds.setUsername("sa");
ds.setPassword("");
ds.setDriverClassName("org.h2.Driver");
return ds;
}
private static SQLManager getSQLManager(){
//得到一个数据源
DataSource dataSource = datasource();
//得到一个ConnectionSource, 单数据源
ConnectionSource source = ConnectionSourceHelper.getSingle(dataSource);
//SQLManagerBuilder 唯一必须的参数就是ConnectionSource
SQLManagerBuilder builder = new SQLManagerBuilder(source);
//命名转化,数据库表和列名下划线风格,转化成Java对应的首字母大写,比如create_time 对应ceateTime
builder.setNc(new UnderlinedNameConversion());
//拦截器,非必须,这里设置一个debug拦截器,可以详细查看执行后的sql和sql参数
builder.setInters(new Interceptor[]{new DebugInterceptor()});
//数据库风格,因为用的是sqlserver,所以使用sqlserver,
builder.setDbStyle(new SqlServerStyle());
SQLManager sqlManager = builder.build();
return sqlManager;
}
public static void main(String[] args) throws Exception {
SQLManager sqlManager = getSQLManager();
//初始化数据脚本,执行后,内存数据库将有一个sys_user表和模拟数据
DBInitHelper.executeSqlScript(sqlManager,"db/schema.sql");
// 得到数据库的所有表
Set<String> all = sqlManager.getMetaDataManager().allTable();
System.out.println(all);
}
}
新建一个POJO对象 com.UserEntity,与sys_user表对应
@Data
@Table(name="sys_user")
public class UserEntity {
@AutoID
private Integer id;
private String name;
private Integer departmentId;
}
这个Pojo对象我们注意到使用了@Table注解,表明了关联的表是sys_user. @Table注解是非必须的,如果符合命名转化(NameConversion).也可以不需要
@AutoID 作用于注解上,表示这是一个自增主键, 其他标识主键的注解还有@AssignID,@SeqID
UserEntity user = sqlManager.unique(UserEntity.class,1);
属性全部更新(未赋值的会被赋值空修改掉)
UserEntity user = sqlManager.unique(UserEntity.class,1);
user.setName("ok123");
sqlManager.updateById(user);
查询部门为1得到所有用户
UserEntity template = new UserEntity();
template.setDepartmentId(1);
List<UserEntity> list = sqlManager.template(template);
String sql = "select * from sys_user where id=?";
Integer id = 1;
SQLReady sqlReady = new SQLReady(sql,new Object[]{id});
List<UserEntity> userEntities = sqlManager.execute(sqlReady,UserEntity.class);
String updateSql = "update department set name=? where id =?";
String name="lijz";
SQLReady updateSqlReady = new SQLReady(updateSql,new Object[]{name,id});
sqlManager.executeUpdate(updateSqlReady);
像MyBatis那样,BeetlSQL 支持模板SQL。
{
String sql = "select * from sys_user where department_id=#{id} and name=#{name}";
UserEntity paras = new UserEntity();
paras.setDepartmentId(1);
paras.setName("lijz");
List<UserEntity> list = sqlManager.execute(sql,UserEntity.class,paras);
}
{
//或者使用Map作为参数
String sql = "select * from sys_user where department_id=#{myDeptId} and name=#{myName}";
Map paras = new HashMap();
paras.put("myDeptId",1);
paras.put("myName","lijz");
List<UserEntity> list = sqlManager.execute(sql,UserEntity.class,paras);
}
模板占位符默认是#{} BeetlSQL会输出"?",如果使用${} 则原样输出内容,这个同MyBatis一致。
模板使用Beetl语法,因此支持复杂的SQL构建
//使用Beetl模板语句
String sql = "select * from sys_user where 1=1 \n" +
"-- @if(isNotEmpty(myDeptId)){\n" +
" and department_id=#{myDeptId}\n" +
"-- @}\n" +
"and name=#{myName}";
Map paras = new HashMap();
paras.put("myDeptId",1);
paras.put("myName","lijz");
List<UserEntity> list = sqlManager.execute(sql,UserEntity.class,paras);
模板默认使用-- @
和 回车
作为定界符,因为--
是sql注释符号,这有助于idea或者其他IDE不会报错
通常业务代码需要根据一定逻辑查询数据库,可以使用Query构造较为复杂的单表条件而避免写SQL
Query<UserEntity> query = sqlManager.query(UserEntity.class);
List<UserEntity> entities = query.andEq("department_id",1)
.andIsNotNull("name").select();
使用LambdaQuery,能很好的支持数据库重构
LambdaQuery<UserEntity> query = sqlManager.lambdaQuery(UserEntity.class);
List<UserEntity> entities = query.andEq(UserEntity::getDepartmentId,1)
.andIsNotNull(UserEntity::getName).select();
这段查询同上段代码是一样的,不同的是使用lambda表达式,这样如果列名重构,则自动会重构这段代码,不需要作手工修改
稍微做个复杂项目的人都知道,把复杂SQL放到专门的SQL里维护是个很好的办法。(BeetlSQL3 提供了专门的插件来维护SQL)
默认情况下,sql文件位于classpath的sql目录下,可以在resources目录下新建一个sql目录,并在sql目录下新建一个user.md文件
内容如下
select
===
```sql
select * from sys_user u where 1=1
-- @ if(isNotEmpty(name)){
and name like #{name}
-- @ }
order by u.id desc
```
如下代码可以访问并执行这个sql语句
SqlId id = SqlId.of("user","select");
Map map = new HashMap();
map.put("name","n");
List<UserEntity> list = sqlManager.select(id,UserEntity.class,map);
sqlManager.select将会查询user.md文件下的select片段,并执行,执行结果映射成UserEntity对象。
一个markdown文件可以包含任意多个sql片段,格式如下
文件一些说明,放在头部可有可无,如果有说明,可以是任意文字
SQL标示
===
以*开头的注释,可选
SQL语句
SQL标示2
===
SQL语句 2
使用SqlId指明sql文件位置不方便,更常见的是在mapper方法里调用
@SqlResource("user") /*sql文件在user.md里*/
public interface UserMapper extends BaseMapper<UserEntity> {
/**
* 调用sql文件user.md#select,方法名即markdown片段名字
* @param name
* @return
*/
List<UserEntity> select(String name);
}
这里的select方法没有任何注解,意思是调用sql文件执行,sql文件通过@SqlResource申明,sql片段名字则同方法名,sql中用的参数则同方法参数,调用起来非常方便
user.md:
selectUserByName
select * from sys_user u where 1=1
-- @ if(isNotEmpty(name)){
and name like #{name}
-- @ }
order by u.id desc
pageQuery
select #{page('*')} from sys_user where 1=1
-- @if(isNotEmpty(deptId)){
and department_id=#{deptId}
-- @}
pageQuery2
group 语句翻页需要转成子查询
select
#{page('*')}
from (
select count(1) total,department_id from sys_user where 1=1
-- @if(isNotEmpty(deptId)){
and department_id=#{deptId}
-- @}
group by department_id
) a
pageQuery3
select #{page()} from sys_user where 1=1
-- @if(isNotEmpty(deptId)){
and department_id=#{deptId}
-- @}
pageQuery3$count
select count(1) from sys_user /* 使用指定的count语句*/
departmentJsonMapping
映射DepartmentInfo
{
"id":"id",
"name":"name",
"users":
{
"id":"u_id",
"name":"u_name"
}
}
public T unique(Class clazz,Object pk) 根据主键查询,如果未找到,抛出BeetlSQLException
异常.
public T single(Class clazz,Object pk) 根据主键查询,如果未找到,返回null.
public List selectByIds(Class clazz, List<?> pks) 根据一批主键查询
public List all(Class clazz) 查询出所有结果集
public List all(Class clazz, int start, int size) 翻页
public int allCount(Class<?> clazz) 总数
public T lock(Class clazz, Object pk) 同single方法,但会得到一个行级锁,行级锁的失效机制取决于事务失效
?
用于占位符,用于in,如