文档章节

Slardar Sql Mapper Framework for Java( Java 持久层框架一枚~)

coder4j
 coder4j
发布于 2017/02/14 00:19
字数 2105
阅读 343
收藏 12

 

      slardar是一个sql mapping框架,其大概使用方式类似mybatis,没有采用hibernate那种orm的方式是因为个人觉得这种方式需要大量的处理sql,每次操作对象都要进行依次sql解析比较繁琐;转而想到mybatis这种把sql逻辑交给用户的方式还是比较合理的。同时又不像全盘照抄mybatis,还是想有一些独特的地方,于是将mybatis的xml配置sql的方式换成了javascript,通过解析javascript来得到sql,并能达到生成动态sql的功能,一举两得。

架构图如下:

虚线部分目前没有实现,目前版本的slardar暂时没有缓存sql执行结果。并且还没有实现缓存淘汰策略,这将是下一个版本要努力做的。

slardar的使用方法和mybatis十分类似,因为大体api的使用设计就是根据它来的。

一. 第一个例子

slardar的使用如下。 假设我们要做一个简单的查询:

首先创建一个和数据库表对应的实体,我们以一个用户表为例。

package org.easyarch.test.pojo;


import org.easyarch.slardar.annotation.entity.Column;
import org.easyarch.slardar.annotation.entity.Table;

@Table(tableName = "user")
public class User {

    @Column(name = "client_id")
    private String clientId;

    @Column(name = "username")
    private String userName;

    @Column(name = "password")
    private String password;

    @Column(name = "phone")
    private String phone;

    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {
        this.clientId = clientId == null ? null : clientId.trim();
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password == null ? null : password.trim();
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone == null ? null : phone.trim();
    }

}

接下来,创建一个mapper接口,通过id对我们的用户表进行查询:

package org.easyarch.test.dao;

import org.easyarch.slardar.annotation.sql.SqlParam;
import org.easyarch.test.pojo.User;

import java.util.List;


public interface UserMapper {

    public User findById(@SqlParam(name = "id") String id);

    public List<User> findByUser(User user);

}

这里@SqlParam注解中的name将是后面sql模板中配置所需要的,接下来我们就可以创建相关的配置文件:

先创建一个  resources/db.properties 文件用来连接我们的数据库:

username = ****
password = ****
url = jdbc:mysql://localhost:3306/testdb?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false
driverClassName = com.mysql.jdbc.Driver

maxActive =100
minIdle = 10
initialSize = 40
maxWait = 6000

接下来配置slardar所需的信息,新建一个 resources/config.xml:

<configuration>
    <interface package="org.easyarch.test.dao" />

    <mapper location="classpath:mapper/" />

    <datasource location="classpath:db.properties" class=""/>
</configuration>

 

然后我们编写一个js文件,mapper/usermapper.js 这样:

ctx.namespace = "org.easyarch.test.dao.UserMapper";

function findById(params){
    return "select * from user where client_id = $id$";
}
function findByUser(params) {
    var sql = "select * from user" + ctx.where;
    if (params.clientId != undefined){
        sql += " and client_id = $clientId$";
    }
    if (params.phone != undefined){
        sql += " and phone = $phone$";
    }
    return sql;
}

ctx.namespace是UserMapper接口名, js方法必须和对应接口方法名同名(参数就不用管了)

然后我们写一个Service类,来初始化操作:

package org.easyarch.test.service;

import org.easyarch.slardar.entity.Parameter;
import org.easyarch.slardar.session.DBSession;
import org.easyarch.slardar.session.DBSessionFactory;
import org.easyarch.slardar.session.DBSessionFactoryBuilder;
import org.easyarch.slardar.utils.ResourcesUtil;
import org.easyarch.test.dao.UserMapper;
import org.easyarch.test.pojo.User;

import java.util.List;

/**
 * Description :
 * Created by xingtianyu on 17-2-9
 * 上午2:22
 * description:
 */

public class UserService {

    private UserMapper mapper;

    private DBSession session;
    

    public UserService(){
        try {
            DBSessionFactory sessionFactory = new DBSessionFactoryBuilder().build(
                    ResourcesUtil.getResourceAsStream("/config.xml"));
            session = sessionFactory.newDelegateSession();
            mapper = session.getMapper(UserMapper.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public User getUser(String id){
        return mapper.findById(id);
    }


    public List<User> getUsers(User user){
        return mapper.findByUser(user);
    }
    
}

最后写一个main函数去调用即可:

package org.easyarch.test.controlle;


public class UserController {

    public static void main(String[] args) throws Exception {
        UserService service = new UserService();
        System.out.println("get user by id:"+service.getUser("123456"));

        User u = new User();
        u.setUserName("code4j");
        u.setPhone("1300000000");
        List<User> users = service.getUsers(u)
        System.out.println("get User by user:"+users.size());
    }


}

这样一个标准的查询和一个动态查询就演示完了。

二. 配置说明

这里介绍一下config.xml配置和js配置相关的说明,如代码:

<configuration>
    <interface package="org.easyarch.test.dao" />

    <mapper location="classpath:mapper/" />

    <datasource location="classpath:db.properties" class=""/>
</configuration>

 

这里注意,interface中的package一定要写接口名所在包,不要写接口名,slardar将会在指定的包下读取接口;如不填写,或之填写 * ,则认为从整个工程开始扫描。

mapper中的location是sql模板文件的路径,也只是写目录即可,不要具体到文件名。这里有三种写法:

    1. classpath:xxxx/xxx/    这种写法默认从类路径下开始找,等同于 getClass().getClassLoader().getResources("").getPath() + "/xxxx/xxx/";    

    2. /opt/web/xxxx  这种是绝对路径写法,也是支持的,windows用户改成相应写法即可。

    3.mapper/   这种写法默认从 config.xml这个文件所在目录开始,从同级的目录开始找,假设config.xml在 /opt/web/admin/ 下, 则这里就是 /opt/web/admin/mapper/

datasource 配置db.properteis 文件的位置,策略同mapper. 后面的class属性可以不写,或写空,默认使用slardar自带的连接池,也可以写其他第三方的连接池datasource类名(目前只支持DBCP和 Druid) 

js配置说明,如代码:

ctx.namespace = "org.easyarch.test.dao.UserMapper";

function findById(params){
    return "select * from user where client_id = $id$";
}
function findByUser(params) {
    var sql = "select * from user" + ctx.where;
    if (params.uesrname != undefined){
        sql += " and username = $userName$";
    }
    if (params.phone != undefined){
        sql += " and phone = $phone$";
    }
    if (params.client_id != undefined){
        sql += " and client_id = $clientId$";
    }
    return sql;
}

1.方法返回必须是sql语句,方法参数 只用来做动态sql,不一定用得上,但是必须要写。

2.ctx.namespace  和 ctx.where 是默认的上下文对象,namespace用来标示唯一的配置文件;

where 的值是 ” where 1 = 1“ 一个永真式,主要是用在动态sql上,消除用户判断每一个条件是否要加and,有了这个变量后用户可以在每个if里面的sql前面都加上and, 无需判断当前if是不是第一个where条件。

3.sql 语句中的 $id$ , $phone$ 等 和参数中的名字对应的,比如UserMapper中id用注解标示 @SqlParam(name="id") 则这里模板写的也是id,不同的是如果参数是对象或Map,则无需使用注解标识。

3.js 在这里起的作 用主要是动态sql的生成,所以本框架中的js只支持基本的逻辑判断,并不支持js其他库的功能。

 

三. 项目链接

github仓库发一下:

github : https://github.com/rpgmakervx/slardar

osc : https://git.oschina.net/rpgmakervx/slardar

说明一下,这个项目其实是从我的另一个项目myutils中剥离出来的,期初就是想封装一套jdbc操作工具,后来做slardar的时候直接在这个项目的jdbc模块写的,后来才迁移出来的。

myutils是我平时积累封装的一些工具库,有一些apache common 或guava 已经有了,但有些功能是他们没有的。 比如反射工具,netty封装的httpclient(使用起来和apache httpclient类似,用future模式实现的),或者一些excel导出的功能等等,积累一些demo以后总是用的上的。

 

下一篇:文档使用篇(配置文件和sql映射配置)

-----------------------------------------我是分割线2017-02-16添加---------------------------------------------

config新增配置方法和配置项:

最新配置demo如下

<?xml version="1.0"?>
<configuration>
    <interface package="org.easyarch.test.dao" />

    <mapper location="classpath:mapper/" />

    <cache enable="true"
           mode="lru"
           size="128"/>

    <!--<datasource location="classpath:db.properties" class="" />-->
    <datasource class="">
        <property name="username" value="root" />
        <property name="password" value="123456" />
        <property name="url" value="jdbc:mysql://localhost:3306/shopping?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false" />
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />

        <property name="maxActive" value="100" />
        <property name="minIdle" value="10" />
        <property name="initialSize" value="40" />
        <property name="maxWait" value="6000" />
    </datasource>
</configuration>

 

1. datasource标签内部可以直接配置db相关信息,如此键值对名可以用户自定义,就能支持所有数据库链接池了。(之前不支持c3p0,是因为它的配置键名和dbcp,druid不一样,我自定义的连接池是跟druid配置方法一样的)

datsource部分可以由用户来自定义。

2.新增cache选项。

enable:表示是否开启二级缓存,二级缓存即查询结果缓存。若开启二级缓存,当输入sql语句与参数完全相同时,会直接从二级缓存获取结果不走数据库查询。不设置该属性默认为false。

mode:表示缓存模式,一共有四种缓存模式,FIFO,LRU,TIMEOUT,默认。分别是先进先出,最近最久未使用,超时。不设置该属性为默认,默认缓存没有大小限制,没有淘汰策略。

size:代表缓存大小,当选择timeout模式时,size代表缓存时间(毫秒)。该值设置小于等于0或不设置该属性时则认为不启用缓存。

不配置cache标签,则不启用二级缓存

总结来说就是:不配置cache标签,不设置size或size非正整数,enable=false或不设置,都不会启用二级缓存

因为有些应用要求一致性比较强,所以在这类应用中注意缓存的使用,一致性很强的业务不要用,要求最终一致性的场景可以适当使用。

© 著作权归作者所有

共有 人打赏支持
coder4j

coder4j

粉丝 20
博文 14
码字总数 24633
作品 0
朝阳
高级程序员
加载中

评论(7)

coder4j
coder4j

引用来自“impins”的评论

鱼人守卫Slardar

回复@impins : 对对对,github上我用的图片就是大鱼人
impins
impins
鱼人守卫Slardar
coder4j
coder4j

引用来自“蓝水晶飞机”的评论

:+1: 方法很赞!
JS是代理到Java接口吗?
JS 函数里面的SQL字符串$param$如何实现替换?

引用来自“coder4j”的评论

1.js方法的执行是通过Java去调起js引擎获取执行结果的,类似Java调用别的脚本一样。至于你定义的Mapper接口,倒是用动态代理去实现的底层查询。
2.$param$ 这个解析是 先做sql解析,获取到右值表达式,然后得到这个标签,解析标签,放到list里面,递归读取这个标签解析,得到一个顺序的结果。
喜欢这个框架的话就去start吧! 感觉有新的建议提给我哦!

引用来自“yong230”的评论

Java去调起js引擎这样很慢的啊
实际上这里使用java调js,一方面是想尝试一下java的这个特性,也许这个特性的性能在目前版本不太好但是在9或更高版本会的到改善;另一方面是不希望完全成为mybatis的样子,否则就没有什么意义了;在就是动态sql用这个确实节省了很多麻烦。
coder4j
coder4j

引用来自“蓝水晶飞机”的评论

:+1: 方法很赞!
JS是代理到Java接口吗?
JS 函数里面的SQL字符串$param$如何实现替换?

引用来自“coder4j”的评论

1.js方法的执行是通过Java去调起js引擎获取执行结果的,类似Java调用别的脚本一样。至于你定义的Mapper接口,倒是用动态代理去实现的底层查询。
2.$param$ 这个解析是 先做sql解析,获取到右值表达式,然后得到这个标签,解析标签,放到list里面,递归读取这个标签解析,得到一个顺序的结果。
喜欢这个框架的话就去start吧! 感觉有新的建议提给我哦!

引用来自“yong230”的评论

Java去调起js引擎这样很慢的啊
这块慢多少我没试过,但是我在调起js这块是做了缓存的。也就是说在初次使用的时候是会比较慢,后面的话会好一些
yong230
yong230

引用来自“蓝水晶飞机”的评论

:+1: 方法很赞!
JS是代理到Java接口吗?
JS 函数里面的SQL字符串$param$如何实现替换?

引用来自“coder4j”的评论

1.js方法的执行是通过Java去调起js引擎获取执行结果的,类似Java调用别的脚本一样。至于你定义的Mapper接口,倒是用动态代理去实现的底层查询。
2.$param$ 这个解析是 先做sql解析,获取到右值表达式,然后得到这个标签,解析标签,放到list里面,递归读取这个标签解析,得到一个顺序的结果。
喜欢这个框架的话就去start吧! 感觉有新的建议提给我哦!
Java去调起js引擎这样很慢的啊
coder4j
coder4j

引用来自“蓝水晶飞机”的评论

:+1: 方法很赞!
JS是代理到Java接口吗?
JS 函数里面的SQL字符串$param$如何实现替换?
1.js方法的执行是通过Java去调起js引擎获取执行结果的,类似Java调用别的脚本一样。至于你定义的Mapper接口,倒是用动态代理去实现的底层查询。
2.$param$ 这个解析是 先做sql解析,获取到右值表达式,然后得到这个标签,解析标签,放到list里面,递归读取这个标签解析,得到一个顺序的结果。
喜欢这个框架的话就去start吧! 感觉有新的建议提给我哦!
蓝水晶飞机
蓝水晶飞机
:+1: 方法很赞!
JS是代理到Java接口吗?
JS 函数里面的SQL字符串$param$如何实现替换?
MyBatis 实践 -Mapper与DAO

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hanqing280441589/article/details/50760236 标签: Java与存储 MyBatis简介 MyBatis前身是iBatis,是一个基于...

菜鸟-翡青
2016/02/28
0
0
MyBatis框架教程「入门起步」

今天我们就踏上学习Mybatis框架的旅程,在SSM框架中Mybatis框架是dao层的一个解决方案。相当于传统Servlet+JavaBean开发模式中JDBC的作用。具体关于MVC架构的知识可以移步「从零学习Spring ...

技术小能手
07/30
0
0
mybatis系统学习(二)——使用基础mybatis代替原始jdbc

mybatis系统学习(二)——使用基础mybatis代替原始jdbc 前言 这一篇笔记的内容应当是建立在上一篇的基础之上,不论是使用的数据表,还是对应的实体类,都在上一篇有过说明。 有兴趣的或者对...

推荐码发放
05/03
0
0
spring-boot、mybatis整合

一、MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配...

小不点丶
2017/08/22
0
0
Mybatis成为首选持久框架的原因

持久层可以将业务数据存储到磁盘,具备长期存储能力,只要磁盘不损坏(大部分的重要数据都会有相关的备份机制),在断电或者其他情况下,重新开启系统仍然可以读取这些数据。一般执行持久任务...

java高级架构技术
06/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

arcgis jsapi接口入门系列:总览

开发环境: arcgis jsapi版本4.9 由于我们这套代码是基于vue,webpack开发的,会有少数vue代码,但总体不影响 里面还有些我们公司的js库和html css,给出的代码不能百分百直接运行,主要还是...

canneljls
5分钟前
0
0
月薪80k阿里架构师漫谈他是如何从一名小码农走到架构师的

01 刚当程序员时,我是属于那种勤勤恳恳类型的员工,工作态度用认真来形容不为过,每天我几乎是团队里最早到公司,又最晚下班的一个。而组员张工一般情况下都是准时上下班的,即使项目进度比...

Java填坑之路
7分钟前
0
0
oracle的resetlogs机制浅析

oracle的resetlogs机制浅析 alter database open resetlogs 这个命令我想大家都很熟悉了,那有没有想过这个resetlogs选项为什么要用?什么时候用? 它的原理机制是什么?他都起哪些作用? 我...

突突突酱
9分钟前
0
0
JAVA 获取两个日期间的所有日期

public static List<String> getDates(String startDate, String endDate){    Date d1 = new SimpleDateFormat("yyyyMMdd").parse(startDate);//定义起始日期    Date d2 = new Simple......

尘叙缘
15分钟前
0
0
Innodb中的事务隔离级别和锁的关系

#一次封锁or两段锁? 因为有大量的并发访问,为了预防死锁,一般应用中推荐使用一次封锁法,就是在方法的开始阶段,已经预先知道会用到哪些数据,然后全部锁住,在方法运行之后,再全部解锁。...

Skqing
29分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部