佳礼资讯网

 找回密码
 注册

ADVERTISEMENT

查看: 1551|回复: 27

数据库存取方法

[复制链接]
发表于 2-12-2008 10:48 PM | 显示全部楼层

回复 7# mokth 的帖子

原来如此 我也用过Spring.NET+NHibernate,普通的Native SQLQuery ADO.NET的确会比较方便....
回复

使用道具 举报


ADVERTISEMENT

发表于 2-12-2008 10:38 PM | 显示全部楼层

回复 6# 苦瓜汤 的帖子

CRUD都用nhibernate来处理了,所以DATALAYER(DAO)只管READ (SELECT 而已,不用负责INSERT/UPDATE/DETELE 的COMMAND). 要做的更美一点,用FACTORY PATTERN 来做DAYALAYER, 把DAYALAYER abstract (hide) 那些SQL COMMAND, 这样一来..file:///C://data.png

[ 本帖最后由 mokth 于 2-12-2008 11:16 PM 编辑 ]
回复

使用道具 举报

 楼主| 发表于 4-12-2008 01:55 PM | 显示全部楼层
原帖由 tensaix2j 于 3-12-2008 04:03 PM 发表


是的。
我们的基础软件跑在linux。
但我们的系统有部分的一些 daemons 要跑在客户  的testerOS ,其中包挂 hpux, linux,solaris, 还有 windows.  

testerOS? 什么系统来的.看来你的工作牵涉了比较底层的软件... 
回复

使用道具 举报

 楼主| 发表于 2-12-2008 01:09 PM | 显示全部楼层 |阅读模式
几乎每个程序都需要数据库或特定的方式来储存持久数据(persistent data), 假设你设计了一个程序需要连接RDBMS数据库存取,你会用什么方法或设计模式?讨论范围不拘,从建立连接,查询,事务处理(Transaction Management)等等

例如:

嵌入式SQL

在需要存取的时候直接把SQL写到代码内。

数据存取层 (Data Access Layer)

将SQL集中在一个逻辑表现层,然后定义接口或API。

ORM (Object Relational Mapping)

利用第三方的Library,把数据和关系转换成对象,或把对象和关系在转回SQL。

ORM + Data Access Object (DAO)

在ORM之上,加多一层自定义逻辑层,加强和自定义ORM的基本操作。

等等。

欢迎分享你的经验或意见,讨论各种方法的利与弊。
回复

使用道具 举报

发表于 2-12-2008 01:20 PM | 显示全部楼层
flexibility 跟 readability 的tradeoff 咯。。还有,直接坎入式的要注意 字串的漏洞咯。

[ 本帖最后由 tensaix2j 于 2-12-2008 01:23 PM 编辑 ]
回复

使用道具 举报

 楼主| 发表于 2-12-2008 01:48 PM | 显示全部楼层

回复 2# tensaix2j 的帖子

你在新加坡做哪一行的??
回复

使用道具 举报

Follow Us
发表于 2-12-2008 02:00 PM | 显示全部楼层
原帖由 苦瓜汤 于 2-12-2008 01:09 PM 发表
几乎每个程序都需要数据库或特定的方式来储存持久数据(persistent data), 假设你设计了一个程序需要连接RDBMS数据库存取,你会用什么方法或设计模式?讨论范围不拘,从建立连接,查询,事务处理(Transaction Manage ...


我用ORM (Object Relational Mapping)
hibernate,
用 spring 来handle
Transaction Management
回复

使用道具 举报

发表于 2-12-2008 03:09 PM | 显示全部楼层

回复 1# 苦瓜汤 的帖子

我是用 nhibernate (ORM) 来 handle Transaction Management (在FRAMEWORK), 在UI LAYER (WEB/WINFORM),我用 DATALAYER/nhibernate (只能READ) 来呈现DATA, 所有的CRUD都用nhibernate来处理. DATALAYER 是用来处理一下比较复杂的SELECT COMMAND(nhibernate 可以处理,可是 比较复杂 ).

[ 本帖最后由 mokth 于 2-12-2008 03:17 PM 编辑 ]
回复

使用道具 举报


ADVERTISEMENT

 楼主| 发表于 2-12-2008 03:36 PM | 显示全部楼层

回复 5# mokth 的帖子

为何只能READ??
回复

使用道具 举报

发表于 3-12-2008 09:11 AM | 显示全部楼层
原帖由 苦瓜汤 于 2-12-2008 01:48 PM 发表 你在新加坡做哪一行的??

某software house 做小小程序员, 
我们的顾客是semicon 的 test houses。
回复

使用道具 举报

 楼主| 发表于 3-12-2008 01:35 PM | 显示全部楼层
原帖由 tensaix2j 于 3-12-2008 09:11 AM 发表

某software house 做小小程序员,
我们的顾客是semicon 的 test houses。

新加坡??
目前在做什么样的platform?
回复

使用道具 举报

 楼主| 发表于 3-12-2008 01:42 PM | 显示全部楼层
Hibernate等ORM Lib有一个问题就是文档要看得很清楚。而且要review每一个generated的SQL,因为有很多调度上的问题可能影响程序的性能。
回复

使用道具 举报

发表于 3-12-2008 04:03 PM | 显示全部楼层
原帖由 苦瓜汤 于 3-12-2008 01:35 PM 发表 新加坡?? 目前在做什么样的platform?
 

是的。
我们的基础软件跑在linux。
但我们的系统有部分的一些 daemons 要跑在客户  的testerOS ,其中包挂 hpux, linux,solaris, 还有 windows. 
回复

使用道具 举报

发表于 5-12-2008 09:41 AM | 显示全部楼层
原帖由 苦瓜汤 于 4-12-2008 01:55 PM 发表 testerOS? 什么系统来的.看来你的工作牵涉了比较底层的软件... 

是客户用来跑 测试程序 的系统。
测试程序是他们的客户提供的。
是的。 但我们介入的部分也没底层到 assembly, 最多只是有用到些 platform specific 的 system calls .
回复

使用道具 举报

 楼主| 发表于 5-12-2008 09:49 AM | 显示全部楼层
DAO(Data Access Object) 是模式设计中的一个主张,主要的功能是提供一个统一的数据存取接口(Interface),同时封装数据层的运作逻辑。如此一来,依赖DAO层的代码可以调用接口的API,任何DAO以下的变动都不会影响上层的代码。提供DAO接口的好处还有就是能够有不同的实现(Implementation). 例如同一个程序里需要用到两个不同的数据库存取方式或权限,对于DAO模式来说这完全不是问题,因为已经有了一个同一个接口,两种不同的方式可以共用同一个API。

这里有个简单的例子:

为了能够对一个汽车数据库进行存取,我定义了一个DbClient和一个DbClientFactory接口, 还有一个Car的DTO (Data Transfer Object)
  1. public interface DbClient<T> {
  2.     void insert(T obj);
  3.     void update(T obj, String newName);
  4.     void delete(T obj);
  5.     T get(String name, Class<T> clazz);
  6. }
复制代码

  1. public interface DbClientFactory {
  2.     <T> DbClient<T> createDbClient(Class<T> clazz);
  3. }
复制代码

  1. public class Car {
  2.     private String name;
  3.    
  4.     public Car(String name) {
  5.         this.name = name;
  6.     }
  7.     /**
  8.      * @return the name
  9.      */
  10.     public String getName() {
  11.         return name;
  12.     }

  13.     /**
  14.      * @param name the name to set
  15.      */
  16.     public void setName(String name) {
  17.         this.name = name;
  18.     }

  19.     @Override
  20.     public String toString() {
  21.         return name;
  22.     }
  23. }
复制代码

DbClientFactory包含一个createDbClient的工厂函数;DbClient则提供了基本的CRUD运作。

有了这个借口,我可以开始我的程序编写:

  1. public class DbTest {
  2.    
  3.     private static Logger log = Logger.getAnonymousLogger();
  4.     /**
  5.      * @param args
  6.      */
  7.     public static void main(String[] args) {
  8.         DbClientFactory factory = null; //to be implemented.
  9.         DbClient<Car> carClient = factory.createDbClient(Car.class);
  10.         
  11.         Car car = new Car("Benz");
  12.         carClient.insert(car);
  13.         carClient.update(car, "BMW");
  14.         
  15.         
  16.         car = carClient.get("BMW", Car.class);
  17.         if(car != null)
  18.             log.info("Car "+car+" found in database!!");
  19.         
  20.         carClient.delete(car);
  21.     }

  22. }
复制代码


基本上到了这步, 主程序已经完成了,现在决定要怎样实现DbClient这个借口。
由于这只是一个学习例子,所以我决定用Sqlite+JDBC做我的数据库存取,实现的代码如下
  1. public class DbClientImpl<T> implements DbClient<T> {

  2.     private String tableName;
  3.     private Connection conn;
  4.    
  5.     private static Logger log = Logger.getLogger(DbClientImpl.class.getName());
  6.    
  7.     public DbClientImpl(Class<T> clazz){
  8.         tableName = clazz.getSimpleName();
  9.         
  10.         try {
  11.             Class.forName("org.sqlite.JDBC");
  12.             //create table
  13.             Statement stmt = getStatement();
  14.             stmt.execute("drop table if exists "+tableName);
  15.             stmt.execute("create table "+tableName+" (name);");
  16.         }catch(XXXXXn ex){
  17.             log.log(Level.SEVERE, "SQL Error", ex);
  18.         }finally{
  19.             close();
  20.         }
  21.     }
  22.     public void delete(T obj) {
  23.         log.info("Deleting object "+obj.toString());
  24.         try {
  25.             PreparedStatement pstmt = getPrepared("delete from "+tableName+" where name = ?");
  26.             pstmt.setString(1, obj.toString());
  27.             pstmt.execute();
  28.         }catch(SQLXXXXXn ex){
  29.             log.log(Level.SEVERE, "Cannot delete record", ex);
  30.         }finally{
  31.             close();
  32.         }
  33.     }

  34.     public T get(String name, Class<T> clazz) {
  35.         log.info("Getting object with name "+name);
  36.         ResultSet rs = null;
  37.         T obj = null;
  38.         try {
  39.             rs = getStatement().executeQuery("select * from "+tableName+" where name='"+name+"';");
  40.             while(rs.next()){
  41.                 Constructor<T> ctor = clazz.getConstructor(String.class);
  42.                 obj = ctor.newInstance(rs.getString("name"));
  43.             }
  44.         }catch(XXXXXn ex){
  45.             log.log(Level.SEVERE, "Cannot find the record", ex);
  46.         }finally{
  47.             if(rs != null){
  48.                 try {rs.close();}catch(XXXXXn ex){}
  49.             }
  50.             close();
  51.         }
  52.         return obj;
  53.     }

  54.     public void insert(T obj) {
  55.         log.info("Inserting object "+obj.toString());
  56.         try {
  57.             PreparedStatement pstmt = getPrepared("insert into "+tableName+" values (?);");
  58.             pstmt.setString(1, obj.toString());
  59.             pstmt.execute();
  60.         }catch(XXXXXn ex){
  61.             log.log(Level.SEVERE, "Cannot insert the record", ex);
  62.         }finally{
  63.             close();
  64.         }
  65.     }

  66.     public void update(T obj, String newName) {
  67.         log.info("Updating object "+obj.toString());
  68.         try {
  69.             PreparedStatement pstmt = getPrepared("update "+tableName+" set name= ? where name= ?;");
  70.             pstmt.setString(1, newName);
  71.             pstmt.setString(2, obj.toString());
  72.             pstmt.execute();
  73.             
  74.             
  75.         }catch(XXXXXn ex){
  76.             log.log(Level.SEVERE, "Cannot update the record", ex);
  77.         }finally{
  78.             close();
  79.         }
  80.     }

  81.     private Statement getStatement() throws SQLXXXXXn {
  82.         initConnection();
  83.         return conn.createStatement();
  84.     }
  85.    
  86.     private PreparedStatement getPrepared(String sql) throws SQLXXXXXn {
  87.         initConnection();
  88.         PreparedStatement pstmt = conn.prepareStatement(sql);
  89.         return pstmt;
  90.     }
  91.    
  92.     private Connection initConnection() throws SQLXXXXXn {
  93.         conn = DriverManager.getConnection("jdbc:sqlite:test.db");
  94.         return conn;
  95.     }
  96.    
  97.     private void close() {
  98.         try {
  99.             conn.close();
  100.         } catch (XXXXXn e) {
  101.             log.log(Level.SEVERE, "SQL Error", e);
  102.         }
  103.     }
  104. }
复制代码


最后剩下DbClientFactory了
  1. public class DbClientFactoryImpl implements DbClientFactory {

  2.     public <T> DbClient<T> createDbClient(Class<T> clazz) {
  3.         return new DbClientImpl<T>(clazz);
  4.     }

  5. }
复制代码


接下来我只需要在主程序加入我的实现就可以了
  1. DbClientFactory factory = new DbClientFactoryImpl();
复制代码


以上例子粗略了展示了DAO层的分离数据库逻辑和业务逻辑的用处,还有接口和实现的分别。
当然,DAO并不是万灵丹,一些情况之下这种模式并不是十分理想,尤其是当对数据库逻辑要求复杂的时候,DAO就会变得越来越庞大,调用和维护起来也不容易。
回复

使用道具 举报

发表于 5-12-2008 01:53 PM | 显示全部楼层
原帖由 苦瓜汤 于 5-12-2008 09:49 AM 发表
DriverManager.getConnection("jdbc:sqlite:test.db"); ...


connection 拿from datasource 比较好。

如 tomcat 的 datasource 实现了 connection pool(连接池),
那你不用每次读取db 都去new connection。
因为new 一个connection 是很重的!
回复

使用道具 举报


ADVERTISEMENT

 楼主| 发表于 5-12-2008 05:08 PM | 显示全部楼层
原帖由 winmxaa 于 5-12-2008 01:53 PM 发表


connection 拿from datasource 比较好。

如 tomcat 的 datasource 实现了 connection pool(连接池),
那你不用每次读取db 都去new connection。
因为new 一个connection 是很重的!


多谢提醒. 因为这是一个简单的Sqlite实现,所以我没用cpool。
不过,在long-run的情况之下,Connection Pool就是一个必需品,没有它的话会严重影响程序的效率。目前公司内的一个Proprietary的程序很明显没用cpool,而且没有很好的清除没用的connection,每当一段时间,db connection就会让JavaVM Heap size overflow。所以,我们不得不重启Tomcat,和vendor反映了这个问题后,他们竟然叫我们买多一个server:@
回复

使用道具 举报

 楼主| 发表于 5-12-2008 05:14 PM | 显示全部楼层
原帖由 tensaix2j 于 5-12-2008 09:41 AM 发表

是客户用来跑 测试程序 的系统。
测试程序是他们的客户提供的。
是的。 但我们介入的部分也没底层到 assembly, 最多只是有用到些 platform specific 的 system calls .


那基本上这是一个generic的testing platform了?可以透露一下它的features或spec吗(如果不是商业机密的话)?很有兴趣知道
回复

使用道具 举报

发表于 5-12-2008 08:45 PM | 显示全部楼层
原帖由 苦瓜汤 于 5-12-2008 05:08 PM 发表

db connection就会让JavaVM Heap size overflow。所以,我们不得不重启Tomcat,和vendor反映了这个问题后,他们竟然叫我们买多一个server ...


如果想要apply connection pool, 可以找我!
回复

使用道具 举报

发表于 5-12-2008 08:48 PM | 显示全部楼层
原帖由 苦瓜汤 于 5-12-2008 05:14 PM 发表


那基本上这是一个generic的testing platform了?可以透露一下它的features或spec吗(如果不是商业机密的话)?很有兴趣知道


其实我都不好意思在你的贴聊天。。。

不过,你是说什么东西generic?
你是指我公司的软件还是客户用的testeros?
客户的 testeros 有很多种的呢,单单是在windows上的
我认识的都有两三种。有一种居然是跑在jvm上的 。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

 

ADVERTISEMENT



ADVERTISEMENT



ADVERTISEMENT

ADVERTISEMENT


版权所有 © 1996-2023 Cari Internet Sdn Bhd (483575-W)|IPSERVERONE 提供云主机|广告刊登|关于我们|私隐权|免控|投诉|联络|脸书|佳礼资讯网

GMT+8, 21-12-2025 05:11 PM , Processed in 0.131822 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表