本架构考虑到与数据库进行数据交互基本都是使用SQL语言,所以基于此封装了一套面向SQL脚本的数据库操作API
面向SQL数据库操作API完全基于JDBC,对SQL的构造也基本上是对字符串的操作
面向SQL数据库操作API支持使用外部SQL,可以使用本地文件、数据库、缓存服务等任何数据存储载体作为存放SQL的容器
面向SQL数据库操作API支持把结果集转换为javabean、MAP、LIST
面向SQL数据库操作API底层全部使用框架自带的数据库会话对象与数据库连接池
本架构基于JDBC简单封装了一套对数据库进行各种操作的API,需要通过继承的方式来使用
只需要在数据库处理程序中继承org.jtry.framework.database.dao.CommonDao类即可
public class UserDaoImpl extends CommonDao implements UserDao {
然后就可以直接使用相关功能方法,本文档只做稍许讲解
如果需要使用SQL从数据库获取一个业务封装的javabean那么可以使用getEntity方法,例子如下
public User getUserInfo(String name) throws SQLException {
select("*");
from("user_info");
and("name = ?", name);
return getEntity(sql(),parameters(), User.class);
}
该方法最低要求传入一个字符串SQL与一个业务javabean的class,条件参数可选
以上例子中使用了SQL构造工具,将在下一章详细讲解
此章节仅需要知道sql()方法可以获取到SQL字符串,parameters()方法可以获取到参数Object数组
如果需要使用SQL从数据库获取一组业务封装的javabean那么可以使用getList方法,例子如下
@Override
public List<User> getUserInfoList() throws SQLException {
select("*");
from("user_info");
return getList(sql(), User.class);
}
该方法最低要求传入一个字符串SQL,业务javabean的class与条件参数可选
该方法如果不传入业务javabean的class那么返回的list将是一个包含每一列数据的Object数组list
如果需要使用SQL从数据库获取一个键为列名值为数据的Map那么可以使用getMap方法,例子如下
@Override
public Map<String, Object> getUserInfoMap(String name) throws SQLException {
select("*");
from("user_info");
and("name = ?", name);
return getMap(sql(), parameters());
}
该方法最低要求传入一个字符串SQL,条件参数可选
如果需要使用SQL从数据库获取一组键为列名值为数据的Map那么可以使用getMaps方法,例子如下
@Override
public List<Map<String, Object>> getUserInfoMapList() throws SQLException {
select("*");
from("user_info");
return getMaps(sql());
}
该方法最低要求传入一个字符串SQL,条件参数可选
如果需要使用SQL从数据库获取一行的数据那么可以使用getValues方法,例子如下
@Override
public Object[] getUserInfoData(String name) throws SQLException {
select("*");
from("user_info");
and("name = ?", name);
return getValues(sql());
}
该方法最低要求传入一个字符串SQL,条件参数可选
如果需要使用SQL从数据库获取一个数据那么可以使用getValue方法,例子如下
@Override
public String getUserName(String name) throws SQLException {
select("name");
from("user_info");
and("name = ?", name);
return getValue(sql(), parameters()).toString();
}
该方法最低要求传入一个字符串SQL,条件参数可选
如果需要使用SQL从数据库获取一列数据那么可以使用getFrist方法,例子如下
@Override
public List<Object> getUserNameList() throws SQLException {
select("name");
from("user_info");
return getFrist(sql());
}
该方法最低要求传入一个字符串SQL,条件参数可选
如果需要使用一个业务javabean向数据库插入这条数据那么可以使用insertEntity方法,例子如下
@Override
public boolean addUserInfo(User user) throws SQLException {
return insertEntity(user) > 0;
}
该方法要求传入一个业务javabean
如果需要使用一个业务javabean向数据库插入这条数据并获得主键ID那么可以使用insertEntityReturnId方法,例子如下
@Override
public int addUserInfoGetId(User user) throws SQLException {
return insertEntityReturnId(user);
}
该方法要求传入一个业务javabean
如果需要使用一个业务javabean更新数据库满足条件的相应行那么可以使用updateEntity方法,例子如下
@Override
public boolean upUserInfo(User User, String name) throws SQLException {
Map<String, Object> condition = new HashMap<>();
condition.put("name", name);
return updateEntity(User, condition) > 0;
}
该方法要求传入一个业务javabean与条件Map
还有其他方法功能与JDBC相关方法完全一致,故不做多余讲解
具体使用方式还请自行摸索
本架构综合考虑了现有SQL语法类型并由此封装了一套SQL构造工具,其设计思想部分参照了mybatis的相关实现
SQL构造工具本身可以由使用者自己实现,只需要继承org.jtry.framework.database.sql.SQLProvider抽象类并实现相关方法就好
但org.jtry.framework.database.dao.CommonDao类已经继承该类并针对各方面场景妥善的实现了
所以凡继承org.jtry.framework.database.dao.CommonDao类的数据库处理程序都可以使用SQL构造工具
SQL构造工具本质只是一个字符串拼接工具
如果需要构造一条插入SQL语句可以使用insert方法与values方法
并通过sql方法获取到以上拼接的字符串结果以及parameters方法获取以上拼接传入的数据,具体例子如下
@Override
public boolean addUserInfo(User user) throws SQLException {
insert("user_info");
values("name", user.getName());
values("age", user.getAge());
return executeUpdate(sql(), parameters()) > 0;
}
如果需要构造一条删除SQL语句可以使用delete方法与各种判断条件方法,具体例子如下
@Override
public boolean delUserInfo(String name) throws SQLException {
delete("user_info");
and("name = ?", name);
return executeUpdate(sql(), parameters()) > 0;
}
判断条件方法的全部用法如下所示
@Override
public boolean delUserInfo(String name) throws SQLException {
delete("user_info");
and("age > 18");// 直接使用字符串作为参数加入条件
and("name = ?", name);// 在字符串中使用?占位符并通过后面的参数传入具体的数据
andIt("len(name) > 4", name != null);// 使用字符串和表达式作为参数,如果表达式返回true该字符串才会拼接
return executeUpdate(sql(), parameters()) > 0;
}
所有判断条件方法都支持以上用法,比如
@Override
public boolean delUserInfo(String name) throws SQLException {
delete("user_info");
or("age > 18");
or("name = ?", name);
orIt("len(name) > 4", name != null);
return executeUpdate(sql(), parameters()) > 0;
}
如果需要构造一条更新SQL语句可以使用update方法和set方法与各种判断条件方法,具体例子如下
@Override
public boolean upUserInfo(User User, String name) throws SQLException {
update("user_info");
set("name = ?", User.getName());
set("age = ?", User.getAge());
setIt("money = ?", User.getMoney() <= 0);
and("name = ?", name);
return executeUpdate(sql(), parameters()) > 0;
}
如果需要构造一条查询SQL语句可以使用select方法和from方法或者leftJoin方法与各种判断条件方法,具体例子如下
@Override
public User getUserInfo(String name) throws SQLException {
select("*");
from("user_info");
and("name = ?", name);
return getEntity(sql(), parameters(), User.class);
}
多表关联可以使用
@Override
public User getUserInfo(String name) throws SQLException {
select("*");
from("user_info as a");
from("class_info as b");
and("a.name = b.name");
and("name = ?", name);
return getEntity(sql(), parameters(), User.class);
}
也可以使用外链的方式
@Override
public User getUserInfo(String name) throws SQLException {
select("*");
from("user_info as a");
leftJoin("class_info as b on a.name = b.name");
and("name = ?", name);
return getEntity(sql(), parameters(), User.class);
}
如果需要分页查询那么直接使用sqlPagination方法获取sql语句并传入当前所在页与每页多少条
@Override
public List<User> getUserInfoList() throws SQLException {
select("*");
from("user_info as a");
from("class_info as b");
and("a.name = b.name");
return getList(sqlPagination(1, 10), User.class);
}
如果需要获取当前结果总数可以使用sqlCount方法获取sql语句
@Override
public Object getUserInfoCount() throws SQLException {
select("*");
from("user_info as a");
from("class_info as b");
and("a.name = b.name");
return getValue(sqlCount());
}
如果是想拼接一条复杂多层级的SQL语句那么请直接使用append方法即可
@Override
public Object getUserInfoCount() throws SQLException {
append(" select conut(*) ");
append(" from user_info as a , class_info an b ");
append(" where a.name = b.name ");
append(" and len(a.name) > 4 ");
return getValue(sql());
纯面向SQL分层嵌套可以节省相当一部分代码量比如
@Override
public Object[] getUserInfoData(String name) throws SQLException {
select("*");
from("user_info");
whereComm(name);
return getValues(sql());
}
@Override
public boolean upUserInfo(User User, String name) throws SQLException {
update("user");
set("name = ?", User.getName());
set("age = ?", User.getAge());
setIt("money = ?", User.getMoney() <= 0);
whereComm(name);
return executeUpdate(sql(), parameters()) > 0;
}
@Override
public boolean delUserInfo(String name) throws SQLException {
delete("user_info");
whereComm(name);
return executeUpdate(sql(), parameters()) > 0;
}
private void whereComm(String
name) {
and("age > 18");
and("name = ?", name);
andIt("len(name) > 4", name != null);
}
又比如
@Override
public Object getUserInfoCount() throws SQLException {
selectComm();
return getValue(sqlCount());
}
@Override
public List<Map<String, Object>> getUserInfoMapList() throws SQLException {
selectComm();
return getMaps(sql());
}
private void selectComm() {
select("*");
from("user_info as a");
leftJoin("class_info as b on a.name = b.name");
}
其他用法请自行摸索
SQL构造工具不仅仅可以在代码中拼接SQL,也支持把SQL放在外部容器中调用
其获取SQL的方式完全基于本架构提供的面向对象数据库操作API
面向对象数据库操作API由使用者实现,所以理论上支持所有数据存放的载体
本架构提供了基于JDBC和mongodb的两种实现
如果不进行指定SQL存放的相应实现,那么默认情况下使用基于JDBC的面向对象数据库操作API实现
该实现会从框架当前的默认数据源中找到以下结构的数据表并从中寻找SQL脚本,如果该表不存在请先创建
CREATE TABLE `zoo_sql_store` (
`code` varchar(30) NOT NULL DEFAULT '',
`sql` text,
PRIMARY KEY (`code`)
)
该表存在两个列“code”和“sql”
code列用来存放外部SQL全局唯一标识,比如使用SQL运行方法的名称
getUserInfoList
sql列用来存放sql脚本格式,比如以下这条查询语句
select * from user_info where name = #{name} and age > #{age}
格式中允许包含“#{”开头以“}”结尾的标识符,中间使用传入的字段名或者javabean的属性名作为标识
然后调用sqlExternal方法传入一个CODE字符串和参数数据就可以获取到这条SQL
@Override
public List<User> getUserInfoList(User user) throws SQLException {
return getList(sqlExternal("getUserInfoList", user), parameters(), User.class);
}
sqlExternal方法会根据传入的CODE从数据库中拿到对应sql列的SQL格式
然后在SQL格式中找到全部以“#{”开头以“}”结尾的字段名”
再依据全部字段名查找传入javabean或者MAP中名称一样的属性,如果其值不为NULL就会添加到此SQL的参数列表
传入的javabean或者MAP可以是多个或者多层,比如这样
@Override
public List<User> getUserInfoList(User user) throws SQLException {
Map<String, Object> tmpMap = new HashMap<>();
ClassInfo classInfo = new ClassInfo();
classInfo.setClassName("A-01");
tmpMap.put("classInfo", classInfo);
tmpMap.put("id", "1458");
return getList(sqlExternal("getUserInfoList", user, tmpMap), parameters(), User.class);
}
sqlExternal方法也可以使用这样的方式
@Override
public List<User> getUserInfoList(User user) throws SQLException {
return getList(sqlExternal("getUserInfoList", "test", 18), parameters(), User.class);
}
使用以上方式会根据可变参数的顺序为SQL格式中同样顺序的标识符赋值,只有传入类型都为基本类型才会生效,切记不可漏传或错传
之后的用法与使用普通SQL构造器一致,但传入了参数一定记得在操作数据库时使用parameters方法获取
如果需要把存放SQL的载体改变为其他实现可以改变配置管理工具中的 架构配置-系统配置 中的以下3个字段