java项目开发在多表情况下的DAO设计问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java项目开发在多表情况下的DAO设计问题相关的知识,希望对你有一定的参考价值。

java开发中,一个DAO可以控制一张表的add,delete,find及update的基本操作,但是在实际的项目开发中,不可能就一张表。我设计一个只能完成最基本的add,delete,find,update的BaseDAO,在针对不同表的复杂操作时,不停地调用BaseDAO里的基本方法来实现复杂的操作。这种做法与一张表一个DAO相比,可以减少大量重复的代码,但有人说这种做法不行,我想听一下大家的看法,说得好就加分。

package com.xxx.web.dao.base;

import java.io.Serializable;
import java.util.LinkedHashMap;

import javax.annotation.Resource;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.xxx.bean.QueryResult;
import com.xxx.utils.GenericsUtils;
/**
* Dao公共类
* @author Administrator
* 本类主要是各个dao实现类的父类,以后写dao实现类时只要继承此类即可
*/
@SuppressWarnings("unchecked")
@Transactional
public abstract class DaoSupport<T> implements Dao<T>

protected Class<T> entityClass = GenericsUtils.getGenericsType(this.getClass());

@Resource protected SessionFactory sessionFactory;//注入SessionFactory实例
/**
* 插入一个实体
* @param o
*/
public void createObject(Object o)
sessionFactory.getCurrentSession().save(o);

/**
* 删除一个实体
* @param o
*/
public void deleteObject(Object o)
sessionFactory.getCurrentSession().delete(o);

/**
* 更新一个实体
* @param o
*/
public void updateObject(Object o)
sessionFactory.getCurrentSession().update(o);

/**
* 查询一个实体
* @param o
*/
@Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED)
public T searchObject(Serializable id)
if(id == null) throw new RuntimeException(this.entityClass.getName()+ ":传入的实体id不能为空");
return (T)sessionFactory.getCurrentSession().get(this.entityClass, id);

@Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED)
public long getCount()
return (Long)sessionFactory.getCurrentSession().createQuery("select count(o) from "+ (this.entityClass.getSimpleName())+ " o").uniqueResult();

@Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED)
public QueryResult<T> getScrollData(int firstindex, int maxresult, LinkedHashMap<String, String> orderby)
return getScrollData(firstindex,maxresult,null,null,orderby);

@Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED)
public QueryResult<T> getScrollData(int firstindex, long maxresult, String wherejpql, Object[] queryParams)
return getScrollData(firstindex,(int) maxresult,wherejpql,queryParams,null);


@Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED)
public QueryResult<T> getScrollData(int firstindex, int maxresult)
return getScrollData(firstindex,maxresult,null,null,null);

/**
* 查询实体,并返回一个结果集
* @param firstIndex 前置索引
* @param maxNum 要查询的数量
* @param wherehql hql语句
* @param params 参数
* @return QueryResult<T>结果集
*
*
* 如果想取出前20条,并以倒序,则hibernate以最后一个为1,
* 比如,数据库中有20条数据,则你取出后10条,并以倒序显示出来,则它的逻辑是20,19,18,.....11,懂了吧,
* 相应的查询语句为
* getScrollData(int firstIndex, int maxNum,orderby)
*
*
*
*/
@Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED)
public QueryResult<T> getScrollData(int firstIndex, int maxNum, String wherehql, Object[] params, LinkedHashMap<String, String> orderby )
QueryResult<T> qr = new QueryResult<T>();
Session session = sessionFactory.openSession();
Query query = session.createQuery(" select o from "+this.entityClass.getSimpleName()+" o " +(wherehql==null ||"".equals(wherehql.trim())?" ":" where "+wherehql)+ buildOrderby(orderby));
if(firstIndex!=-1 && maxNum!=-1)

query.setFirstResult(firstIndex-1).setMaxResults(maxNum);

setParams(query, params);
qr.setResultList(query.list());
query = session.createQuery(" select count(o) from "+this.entityClass.getSimpleName()+" o " +(wherehql==null ||"".equals(wherehql.trim())?" ":" where "+wherehql));

setParams(query, params);
qr.setTotalRecord((Long)query.uniqueResult());
session.close();
return qr;

给分,你的分太少了
参考技术A 我现在的做法是一个表对应一个DAO,代码重复不怕。因为我有自己的根据数据库结构自动生成代码的工具,所以无所谓。但是当涉及多表操作的时候,我的做法是采用视图,然后针对每个视图同样可以自动生成DAO。
但是有时候,视图涉及到的列太大,例如有blob字段,这时会降低查询效率。针对这种情况,就只有自己写DAO了。
我的准则就是sql语句,一定要尽量集中,不要分散,方便维护。
参考技术B 每个dao实现BaseDao挺好的,但是每个dao还是实现一个表的CRUD。
在此基础上,建立manager层,甚至建立service层,在这两个层中再组合各个dao,完成复杂数据库操作。这样便于开发,便于事务配置。也便于领域对象和映射对象的分离。
参考技术C 一个dao就负责一个表太浪费了。应该按照业务需要写相应的dao,这样可以保证dao容易重用。 参考技术D 可行不可行在打乎你对抽象架构的理解和对项目本身的掌握.一些企业级的应用就是用抽象继承的办法来精简代码.这用最简单的多态反射机制就能做到,问题是你能不能合理地抽象出最高层抽象基础架构,能不能用一套统一的框架来解决你在项目上遇到的大部分的问题.所以总体来说,你这种想法是对的.但同时也应当要注意到一些公用的代码可以复用,但对于一些针对特殊业务逻辑的代码就不能精简.也就是说代码可以部分精简,但不可能全部精简,这也是为什么有些人说不行的原因.本回答被提问者采纳

关于mybatis+sqlserver 的多表关联的分页(注意要先分页在多表关联)

 在这里浅谈下mybatis+sqlserver 遇到的小坑,当我们在mapper.xml 中写sql 语句 取参的时候注意不能用#{}去取值
top 关键字是不支持的 然后会报java.sql.SQLException: ‘@P0‘ 附近有语法错误 只能用${}去取值
SELECT * FROM(
    SELECT TOP ${pageSize}* FROM st_student s
    WHERE s.stu_id NOT IN  (
    SELECT TOP ${pageId} s.stu_id FROM st_student s ORDER BY s.stu_id ASC
    )ORDER BY s.stu_id ASC
    )as a
    left join st_stucourse sc
    on a.stu_id=sc.stu_id
    left join st_course c
    on sc.co_id=c.co_id 


--
准备数据 -- 创建数据库 create database EASTETWO; use EASTETWO go create table st_student( stu_id int not null primary key IDENTITY(1,1), stu_name varchar(30), stu_s int not null, stu_birth datetime, stu_birthplace varchar(30), stu_email varchar(20) ) go select * from st_student; go set identity_insert st_student ON; go insert into st_student (stu_id,stu_name,stu_s,stu_birth,stu_birthplace,stu_email) values(1,小张,1,2016-12-28,上海,[email protected]); insert into st_student (stu_id,stu_name,stu_s,stu_birth,stu_birthplace,stu_email) values(2,小华,1,2016-12-27,上海,[email protected]); insert into st_student (stu_id,stu_name,stu_s,stu_birth,stu_birthplace,stu_email) values(3,小明,1,2016-12-26,上海,[email protected]); insert into st_student (stu_id,stu_name,stu_s,stu_birth,stu_birthplace,stu_email) values(4,小文,1,2016-11-28,上海,[email protected]); insert into st_student (stu_id,stu_name,stu_s,stu_birth,stu_birthplace,stu_email) values(5,小郭,1,2016-11-26,上海,[email protected]); insert into st_student (stu_id,stu_name,stu_s,stu_birth,stu_birthplace,stu_email) values(6,小刘,1,2016-10-28,上海,[email protected]); insert into st_student (stu_id,stu_name,stu_s,stu_birth,stu_birthplace,stu_email) values(7,小雯,1,2016-10-27,上海,[email protected]); go set identity_insert st_student off; go --创建课程表 create table st_course( co_id int not null primary key IDENTITY(1,1), co_name varchar(30) ) go use EASTETWO; select * from st_student; create table st_stucourse( id int not null primary key IDENTITY(1,1), stu_id int not null, co_id int not null, co_score int not null ) go -- 在这里注意当插入数据的时候 一定要将 identity_insert 开启 set identity_insert st_stucourse ON go insert into st_stucourse (id,stu_id,co_id,co_score) values(10,1,1,90); insert into st_stucourse (id,stu_id,co_id,co_score) values(11,1,2,70); insert into st_stucourse (id,stu_id,co_id,co_score) values(12,1,3,88); insert into st_stucourse (id,stu_id,co_id,co_score) values(13,1,4,88); insert into st_stucourse (id,stu_id,co_id,co_score) values(14,1,5,98); insert into st_stucourse (id,stu_id,co_id,co_score) values(6,2,2,88); insert into st_stucourse (id,stu_id,co_id,co_score) values(7,2,3,90); insert into st_stucourse (id,stu_id,co_id,co_score) values(8,2,4,99); insert into st_stucourse (id,stu_id,co_id,co_score) values(9,2,6,88); -- 执行完一定要关闭 否则在另一张表会报错 set identity_insert st_stucourse OFF go select * from st_stucourse; set identity_insert st_course ON go insert into st_course (co_id,co_name) values(1,历史); go insert into st_course (co_id,co_name) values(2,数学); insert into st_course (co_id,co_name) values(3,语文); insert into st_course (co_id,co_name) values(4,英语); insert into st_course (co_id,co_name) values(5,地理); insert into st_course (co_id,co_name) values(6,政治); go set identity_insert st_course OFF go go -- 在实际开发中最好不要用* SELECT * FROM( SELECT TOP 10* FROM st_student s WHERE s.stu_id NOT IN ( SELECT TOP 0 s.stu_id FROM st_student s ORDER BY s.stu_id DESC ) ORDER BY s.stu_id DESC )as a left join st_stucourse sc on a.stu_id=sc.stu_id left join st_course c on sc.co_id=c.co_id go -- 遇到的坑就是先分页还是先关联 如果你先关联表(如果有一 对异常多的) 那么你在前台页面会遇到 -- 个问题就是在显示第一页的数据时会出现显示的记录数会少于我们的要求显示的记录数 go SELECT TOP 10 * FROM st_student s, st_stucourse sc, st_course c where s.stu_id=sc.stu_id and sc.co_id=c.co_id and s.stu_id NOT IN ( SELECT TOP 0 s.stu_id FROM st_student s ORDER BY s.stu_id DESC ) ORDER BY s.stu_id DESC go -- row_number() 会效率更高些 use EASTETWO; select * from ( select top 10 * from ( select row_number() over(order by s.stu_id DESC) as rownumber,* from st_student s ) A where rownumber > 0 )as a left join st_stucourse sc on a.stu_id=sc.stu_id left join st_course c on sc.co_id=c.co_id

 















以上是关于java项目开发在多表情况下的DAO设计问题的主要内容,如果未能解决你的问题,请参考以下文章

MySQL基础:多表查询

java中一张表必须有个对应的dao吗

面向对象编程和DAO设计模式

校园商铺-2项目设计和框架搭建-7验证Dao

spring项目篇15 --- 商城小项目创建订单以及查看所有订单

Django model 遇到查询条件组合比较多的情况下怎么写