一个简单的通用dao层工具 - 简书
一个简单的通用dao层工具
通用性的思考要如何做到dao层与数据库和表无关是一个很值得思考的问题,如果想要偷懒,不为每个业务都编写特定的dao层实现,就必须要考虑所有可能会出现的情况。关于sql语句其实要谈论的不是通不通用,因为sql语句就已经是最通用,最灵活的数据库操作实现了,因为你可以用它操作任何数据库只要你写出对应的sql语句。但是正是因为sql语句太灵活,所以编写很麻烦,而且业务的不同导致数据库表的不同,则sql语句也必定会不同,即便一个业务很简单,你也几乎无法重用以前写过的sql语句。
因此我在程序中要做的就是,以java代码的思维去实现数据库操作,并且不为用户暴露过多的实现细节,所谓不暴露过多的细节是指方法的参数不要太复杂,使方法简单易用,同时能满足一些经常出现的业务。底层当然采用的是拼接sql的形式,最终达到的效果是,即便你不是很懂sql语句,只要你懂java,不写sql,也可以操作数据库。
于是我便有了这个接口的设计:
* Created by liuruijie on .
* 能满足数据库的多种操作的通用的dao层接口
public interface CommonDao&T& {
* 根据主键查询一条数据
* @param tableName 表名
* @param pkName 主键字段名
* @param id 值
* @param type 要转换的返回类型
* @return 将记录转换成的po类的实例
T selectById(String tableName, String pkName, String id, Class&T& type);
* 根据查询条件查询记录
* List&Student& students = commonDao
.selectByCriteria("m_student"
, commonDao.createCriteria()
.not().like("id", "2013")
.between("age", 10, 20)
.not().eq("gender", "F")
, Student.class);
* @param tableName 表名
* @param criteria 查询条件
* @param type 类型
* @return 将记录转换成的po类的实例的列表
List&T& selectByCriteria(String tableName, Criteria criteria, Class&T& type);
* 查询记录数
* @param tableName 表名
* @param criteria 查询条件
* @return 记录数
long countByCriteria(String tableName, Criteria criteria);
* 根据主键删除一条记录
* @param tableName 表名
* @param pkName 主键字段名
* @param id 主键值
* @return 影响行数 0或1
int removeById(String tableName, String pkName, String id);
* 保存一个对象为一条数据库记录
* 如果对象主键不存在,则会新建
* 如果对象主键已经存在,则会更新
* @param tableName 表名
* @param pkName 主键字段名
* @param entity 要保存的对象实体
* @return 影响行数 0或1
int save(String tableName, String pkName, T entity);
* 查询条件
interface Criteria{
* 使接下来的条件取非
Criteria not();
* 使与下一个条件的连接词变为or,默认为and
Criteria or();
* @param field 字段名
* @param val 值
Criteria eq(String field, Object val);
* 字符串匹配
* @param field 字段名
* @param val 值
Criteria like(String field, Object val);
* 取两个值之间的值
* @param field 字段名
* @param val1 值1
* @param val2 值2
Criteria between(String field, Object val1, Object val2);
* 限制查询记录数
* @param start 开始位置
* @param row 记录数
Criteria limit(int start, int row);
* 获取参数列表
* @return 参数列表
List&Object& getParam();
* 获取拼接好的where条件sql语句
* @return sql
StringBuilder getCriteriaSQL();
* 让实现类自己实现建立条件的方法
* @return 查询条件实例
Criteria createCriteria();
这个接口提供了最常用的一些操作:根据主键查询记录,多条件查询,删除一条记录,更新记录以及插入记录,而且都是能满足大多数业务的,并且需要用户提供的参数也不多。当然要做到简单,就必须要舍弃一些不常见的细节,比如说这里我就只考虑了单主键的情况。当然这些都可以不断地完善,一开始就做出十全十美的东西是肯定不可能的。接下来看一下实现:
* Created by liuruijie on .
* 通用dao层接口的实现
public class CommonDaoImpl&T& implements CommonDao&T&{
JdbcTemplate jdbcT
public T selectById(String tableName, String pkName, String id, Class&T& type) {
Map&String, Object& obj = jdbcTemplate.queryForMap("SELECT * FROM "+tableName+" WHERE "+pkName+" = ?", id);
return ObjectUtil.mapToObject(obj, type);
public List&T& selectByCriteria(String tableName, CommonDao.Criteria criteria, Class&T& type) {
StringBuilder sqlStr = new StringBuilder("");
sqlStr.append("SELECT * FROM ")
.append(tableName)
.append(criteria.getCriteriaSQL());
System.out.println(sqlStr.toString());
Object[] params = criteria.getParam().toArray(new Object[criteria.getParam().size()]);
List&Map&String, Object&& objs = jdbcTemplate.queryForList(sqlStr.toString(), params);
List&T& results = new ArrayList&&();
for(Map&String, Object& o: objs){
results.add(ObjectUtil.mapToObject(o, type));
public long countByCriteria(String tableName, CommonDao.Criteria criteria) {
String sql = "SELECT COUNT(*) AS num FROM "+tableName + criteria.getCriteriaSQL();
Map&String, Object& map = jdbcTemplate.queryForMap(sql, criteria.getParam().toArray());
return (Long)map.get("num");
public int removeById(String tableName, String pkName, String id) {
String sql = "DELETE FROM " +
tableName +
" WHERE " +
return jdbcTemplate.update(sql, id);
public int save(String tableName, String pkName, T entity) {
Map&String, Object& obj = ObjectUtil.objectToMap(entity);
StringBuffer sql1 = new StringBuffer("INSERT INTO ")
.append(tableName)
.append("(");
StringBuffer sql2 = new StringBuffer(" VALUES(");
List&Object& args = new ArrayList&&();
int count = 0;
for(String key: obj.keySet()){
Object arg = obj.get(key);
if (arg==null){
sql1.append(key).append(",");
sql2.append("?,");
args.add(arg);
sql1.deleteCharAt(sql1.length() - 1);
sql1.append(") ");
sql2.deleteCharAt(sql2.length() - 1);
sql2.append(") ");
String sql = sql1.append(sql2).toString();
System.out.println(sql);
count += jdbcTemplate.update(sql, args.toArray());
}catch (DuplicateKeyException e){
sql1 = new StringBuffer("UPDATE ")
.append(tableName)
.append(" SET ");
sql2 = new StringBuffer(" WHERE "+pkName+"=?");
args = new ArrayList&&();
for (String key: obj.keySet()){
if (key.equals(pkName)){
Object arg = obj.get(key);
if (arg==null){
sql1.append(key).append("=?,");
args.add(arg);
sql1.deleteCharAt(sql1.length() - 1);
args.add(obj.get(pkName));
sql = sql1.append(sql2).toString();
System.out.println(sql);
count+=jdbcTemplate.update(sql, args.toArray());
public CommonDao.Criteria createCriteria() {
return new Criteria();
* 查询条件的实现
class Criteria implements CommonDao.Criteria{
//是否标记了非
p //是否正在拼接第一个条件
//是否修改连接词为OR
StringBuilder criteriaSQL; //从where开始的条件sql
List&Object& //参数列表
String limitS //限制条数
public Criteria(){
criteriaSQL = new StringBuilder("");
param = new LinkedList&&();
limitStr = "";
public Criteria not(){
public CommonDao.Criteria or() {
private void link(){
//判断是否是第一个条件
// ,如果是就加WHERE不加连接词
// ,不是就直接加连接词
if(begin){
criteriaSQL.append(" WHERE ");
criteriaSQL.append(" OR ");
criteriaSQL.append(" AND ");
public Criteria eq(String field, Object val) {
if (not) {
criteriaSQL.append(field)
.append(" != ?");
criteriaSQL.append(field)
.append(" = ?");
param.add(val);
public Criteria like(String field, Object val){
criteriaSQL.append(field)
.append(" NOT LIKE ?");
criteriaSQL.append(field)
.append(" LIKE ?");
param.add("%"+val+"%");
public Criteria between(String field, Object val1, Object val2){
criteriaSQL.append(field)
.append(" NOT BETWEEN ? AND ? ");
criteriaSQL.append(field)
.append(" BETWEEN ? AND ? ");
param.add(val1);
param.add(val2);
public CommonDao.Criteria limit(int start, int row) {
limitStr = " limit " + start + "," +
public List&Object& getParam(){
return this.
public StringBuilder getCriteriaSQL(){
return new StringBuilder(criteriaSQL.toString()+limitStr);
实现使用了spring的jdbcTemplate,其实也可以用最原始的jdbc来实现,虽然麻烦一点,但可以减少依赖。只要接口设计合理,实现起来无非就是一些字符串的拼接,不会太复杂。这里面用到了map和对象互转的工具,为了偷懒,我两个转换方法的实现我是采用的fastjson中序列化json的方法来转换的。
* Created by liuruijie on .
* 对象工具
public class ObjectUtil {
* 对象转字典
public static Map&String, Object& objectToMap(Object obj){
return (Map&String, Object&) JSON.toJSON(obj);
* 字典转对象
public static &T& T mapToObject(Map&String, Object& map, Class&T& T){
return (T) JSON.parseObject(JSON.toJSONString(map), T);
写在最后的一些感受可能会有人觉得,为什么不用ORM框架来做dao层接口,也同样很简单,很方便。这样说吧,以前我是使用的mybatis来做的数据库访问层,并且使用了它的插件mybatisGenerator来做的根据数据库,逆向生成代码,不得不承认它确实很方便,可同样可以做到不写一条sql语句就能够操作数据库。但是用到后来,每个表对应至少一个po类+一个xml文件+一个dao接口+一个Example条件类,到业务越来越复杂,这些东西也就越来越多,然后你就会发现这种自动生成的代码几乎是不能维护的。而且它为你生成了太多无用的代码,要想精简代码,还是必须要自己写sql语句。虽然使用流行的框架,不仅让写代码更方便,还能保证稳定性,而且自己写sql语句还能进行优化,提高执行效率,但是请想一想,有多少人能写出高性能的sql语句呢,对于一些普通的业务,如:xxx人员管理系统,xxx图书管理系统等,这些小型项目,高性能的sql语句又能使其得到多大的提升呢。我的一贯思路都是,实现优先,然后考虑扩展性和可重用性,然后考虑稳定性,最后才考虑性能问题。能让程序在最短的时间内能运行起来才是最重要的,而不是为了提升程序在运行时的速度,而使用复杂的实现,导致迟迟不能运行,最后由于代码考虑的因素过多,把自己搞晕。
到此,我在后端的方向将一个web项目的结构设计从前后端的交互,到业务层的异常处理,再到数据访问层的设计都给出了自己的思路。虽然不是很完美,但是对于我自己来说,这个设计还是挺使用的,这3篇文章中提到的设计思路几乎都是可以运用于各种项目中的。
代码只是工具,思路最重要。
做一个会思考的程序员。当前位置:
→ 跑跑卡丁车无法连接到服务器怎么办 连接服务器失败解决方法
跑跑卡丁车无法连接到服务器怎么办 连接服务器失败解决方法
跑跑卡丁车无法连接到服务器怎么办?这个问题,相信很多跑跑卡丁车玩家曾经遇到过,毕竟作为一款已经运营9年的竞速网游,跑跑卡丁车也曾有关一段非常辉煌的时期,接下来当游戏哦啊吧就给大家介绍一下跑跑卡丁车无法连接服务器解决方法,希望能够帮助到有需要的小伙伴。
跑跑无法连接到服务器怎么办 连接服务器失败解决方法?这个问题,相信很多跑跑卡丁车玩家曾经遇到过,毕竟作为一款已经运营9年的竞速网游,跑跑卡丁车也曾有关一段非常辉煌的时期,接下来戏哦啊吧就给大家介绍一下跑跑卡丁车无法连接服务器解决方法,希望能够帮助到有需要的小伙伴。 跑跑卡丁车无法连接到服务器怎么办 连接服务器失败解决方法:方法1:右键点击网上邻居,选中属性;右键点击本地连接,选中属性;选中“internet协议(TCP/IP)”,点属性;点击高级;选中WINS。 将“启用LMHOSTS查询”前的对勾去掉(就是没有对勾),这样就应该可以了 ,对部分机器有效方法2:检查电脑防火墙,试着关闭再进游戏看看方法3:关闭一些占内存和流量的进程方法4:试试一网游加速工具
读完这篇文章后,您心情如何?
类型: 赛车游戏
大小: 28.0M
语言: 英文
游戏攻略推荐
游戏攻略排行榜
单机游戏排行榜
1 7.3类型: 模拟经营语言: 中文大小: 34.3M
2 7.6类型: 休闲益智语言: 中文大小: 53.7M
3 8.0类型: 即时战略语言: 中文大小: 1.08G
4 6.7类型: 动作冒险语言: 中文大小: 838.4M
5 7.7类型: 射击游戏语言: 中文大小: 414.2M
6 7.8类型: 动作冒险语言: 中文大小: 1.72G
7 6.3类型: 角色扮演语言: 中文大小: 1.91G
8 7.2类型: 休闲益智语言: 中文大小: 103.0M
9 7.7类型: 赛车游戏语言: 中文大小: 439.6M
10 7.2类型: 休闲益智语言: 中文大小: 91.1M
1 6.4类型: 策略游戏语言: 中文大小: 129.4M
2 6.7类型: 动作冒险语言: 中文大小: 838.4M
3 8.0类型: 即时战略语言: 中文大小: 1.08G
4 7.3类型: 模拟经营语言: 中文大小: 34.3M
5 7.2类型: 休闲益智语言: 中文大小: 54.0M
6 7.8类型: 动作冒险语言: 中文大小: 1.72G
7 7.6类型: 休闲益智语言: 中文大小: 53.7M
8 7.2类型: 休闲益智语言: 中文大小: 91.1M
9 1.9类型: 策略游戏语言: 中文大小: 92.9M
10 7.8类型: 动作冒险语言: 中文大小: 69.6M
1 7.3类型: 模拟经营语言: 中文大小: 34.3M
2 7.2类型: 休闲益智语言: 中文大小: 54.0M
3 5.6类型: 动作冒险语言: 中文大小: 2.53G
4 7.7类型: 赛车游戏语言: 中文大小: 439.6M
5 5.1类型: 动作冒险语言: 中文大小: 1.03G
6 7.8类型: 射击游戏语言: 中文大小: 6.61G
7 8.5类型: 角色扮演语言: 繁体中文大小: 9.63G
8 7.1类型: 休闲益智语言: 中文大小: 45.3M
9 7.8类型: 动作冒险语言: 中文大小: 189.4M
10 3.3类型: 休闲益智语言: 中文大小: 44.4M
超多下载基地 当游网()
越当越快乐
版权所有 浙ICP备号