|
查看: 1551|回复: 27
|
数据库存取方法
[复制链接]
|
|
|
发表于 2-12-2008 10:48 PM
|
显示全部楼层
回复 7# mokth 的帖子
原来如此 我也用过Spring.NET+NHibernate,普通的Native SQLQuery ADO.NET的确会比较方便.... |
|
|
|
|
|
|
|
|
|
|
发表于 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? 什么系统来的.看来你的工作牵涉了比较底层的软件... |
|
|
|
|
|
|
|
|
|
|
几乎每个程序都需要数据库或特定的方式来储存持久数据(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-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 编辑 ] |
|
|
|
|
|
|
|
|
|
|

楼主 |
发表于 2-12-2008 03:36 PM
|
显示全部楼层
|
|
|
|
|
|
|
|
|
|
发表于 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)
- public interface DbClient<T> {
- void insert(T obj);
- void update(T obj, String newName);
- void delete(T obj);
- T get(String name, Class<T> clazz);
- }
复制代码
- public interface DbClientFactory {
- <T> DbClient<T> createDbClient(Class<T> clazz);
- }
复制代码
- public class Car {
- private String name;
-
- public Car(String name) {
- this.name = name;
- }
- /**
- * @return the name
- */
- public String getName() {
- return name;
- }
- /**
- * @param name the name to set
- */
- public void setName(String name) {
- this.name = name;
- }
- @Override
- public String toString() {
- return name;
- }
- }
复制代码
DbClientFactory包含一个createDbClient的工厂函数;DbClient则提供了基本的CRUD运作。
有了这个借口,我可以开始我的程序编写:
- public class DbTest {
-
- private static Logger log = Logger.getAnonymousLogger();
- /**
- * @param args
- */
- public static void main(String[] args) {
- DbClientFactory factory = null; //to be implemented.
- DbClient<Car> carClient = factory.createDbClient(Car.class);
-
- Car car = new Car("Benz");
- carClient.insert(car);
- carClient.update(car, "BMW");
-
-
- car = carClient.get("BMW", Car.class);
- if(car != null)
- log.info("Car "+car+" found in database!!");
-
- carClient.delete(car);
- }
- }
复制代码
基本上到了这步, 主程序已经完成了,现在决定要怎样实现DbClient这个借口。
由于这只是一个学习例子,所以我决定用Sqlite+JDBC做我的数据库存取,实现的代码如下
- public class DbClientImpl<T> implements DbClient<T> {
- private String tableName;
- private Connection conn;
-
- private static Logger log = Logger.getLogger(DbClientImpl.class.getName());
-
- public DbClientImpl(Class<T> clazz){
- tableName = clazz.getSimpleName();
-
- try {
- Class.forName("org.sqlite.JDBC");
- //create table
- Statement stmt = getStatement();
- stmt.execute("drop table if exists "+tableName);
- stmt.execute("create table "+tableName+" (name);");
- }catch(XXXXXn ex){
- log.log(Level.SEVERE, "SQL Error", ex);
- }finally{
- close();
- }
- }
- public void delete(T obj) {
- log.info("Deleting object "+obj.toString());
- try {
- PreparedStatement pstmt = getPrepared("delete from "+tableName+" where name = ?");
- pstmt.setString(1, obj.toString());
- pstmt.execute();
- }catch(SQLXXXXXn ex){
- log.log(Level.SEVERE, "Cannot delete record", ex);
- }finally{
- close();
- }
- }
- public T get(String name, Class<T> clazz) {
- log.info("Getting object with name "+name);
- ResultSet rs = null;
- T obj = null;
- try {
- rs = getStatement().executeQuery("select * from "+tableName+" where name='"+name+"';");
- while(rs.next()){
- Constructor<T> ctor = clazz.getConstructor(String.class);
- obj = ctor.newInstance(rs.getString("name"));
- }
- }catch(XXXXXn ex){
- log.log(Level.SEVERE, "Cannot find the record", ex);
- }finally{
- if(rs != null){
- try {rs.close();}catch(XXXXXn ex){}
- }
- close();
- }
- return obj;
- }
- public void insert(T obj) {
- log.info("Inserting object "+obj.toString());
- try {
- PreparedStatement pstmt = getPrepared("insert into "+tableName+" values (?);");
- pstmt.setString(1, obj.toString());
- pstmt.execute();
- }catch(XXXXXn ex){
- log.log(Level.SEVERE, "Cannot insert the record", ex);
- }finally{
- close();
- }
- }
- public void update(T obj, String newName) {
- log.info("Updating object "+obj.toString());
- try {
- PreparedStatement pstmt = getPrepared("update "+tableName+" set name= ? where name= ?;");
- pstmt.setString(1, newName);
- pstmt.setString(2, obj.toString());
- pstmt.execute();
-
-
- }catch(XXXXXn ex){
- log.log(Level.SEVERE, "Cannot update the record", ex);
- }finally{
- close();
- }
- }
- private Statement getStatement() throws SQLXXXXXn {
- initConnection();
- return conn.createStatement();
- }
-
- private PreparedStatement getPrepared(String sql) throws SQLXXXXXn {
- initConnection();
- PreparedStatement pstmt = conn.prepareStatement(sql);
- return pstmt;
- }
-
- private Connection initConnection() throws SQLXXXXXn {
- conn = DriverManager.getConnection("jdbc:sqlite:test.db");
- return conn;
- }
-
- private void close() {
- try {
- conn.close();
- } catch (XXXXXn e) {
- log.log(Level.SEVERE, "SQL Error", e);
- }
- }
- }
复制代码
最后剩下DbClientFactory了
- public class DbClientFactoryImpl implements DbClientFactory {
- public <T> DbClient<T> createDbClient(Class<T> clazz) {
- return new DbClientImpl<T>(clazz);
- }
- }
复制代码
接下来我只需要在主程序加入我的实现就可以了
- 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 是很重的! |
|
|
|
|
|
|
|
|
|
|

楼主 |
发表于 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上的 。。 |
|
|
|
|
|
|
|
|
| |
本周最热论坛帖子
|