数据库API的封装
来源:互联网 发布:阿拉善see基金会 知乎 编辑:程序博客网 时间:2024/06/05 01:00
对于要使用数据库的应用来说,一般会由数据库的开发人员提供一套封装好的API而非直接操作数据库,这样上层应用便不太需要关心如何进行数据的存取等细节问题,更好的代码的封装有利于提高其重用性、可维护性等。当然,对此问题Hibernate[hbnt]已提供了足够的支持,它提供分页[hbpg]、缓存机制[hbch]。但若由于各种原因,不能或不想使用hibernate的话,可自己提供一套。
1 Hibernate
先简单了解下hibernate做的工作,那么自己要写的接口也是类似的。
Hibernate会根据表的字段,生成一个数据库表到Java对象的映射文件,据此映射文件再生成对应的Java类及DAO(DataAccess Objects,数据访问对象)。
对于一个简单 Student表,生成的映射文件如下:
<?xml version="1.0"encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="examble.hibernatemap.Student" table="STUDENT"schema="COLLEGE">
<id name=" id" type="java.lang.String">
<column name="ID"length="40" />
<generatorclass="assigned" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME"length="40" not-null="true" />
</property>
<set name="courses"inverse="true">
<key>
<column name="SID" length="40" />
</key>
<one-to-many class="sample.hibernatemap.StudentCourse"/>
</set>
</class>
</hibernate-mapping>
注:
如果还存在一对多/多对多关系的话,如一个学生可选择多个课程,Student跟 StudentCourse存在一对多关系,则在property元素之后还会有一个set元素,如上面xml文件中的灰色阴影部分。
DAO的接口如下(增加了一个简单的测试),仍对应数据库中的增删查改:
public class StudentDAO {
//添加一个学生
publicstatic boolean save(Student aStudent) {…}
//添加一个学生
publicstatic boolean update(Student aStudent){…}
//删除一个学生
publicstatic boolean deleteById(String id) {…}
//获取所有学生
publicstatic List<Student> findAll() {..}
//获取某个学生
publicstatic Student findById(String id) {…}
//根据某个属性获取学生
publicstatic List< Student > findByField(String fieldname, String fieldvalue) {
//根据特定查询语句获取学生
publicstatic List< Student > findBySql(String sqlStr) {…}
//一个简单的测试
public staticvoid main(String[] args) {
//增加一名学生
Studentstudent = new Student(“001”, “Zhang San”);
booleanresident = StudentDAO.save(student);
System.out.println(“save: ” + result);
}
}
下面是一个实际的例子:
2 代码1 ,数据库操作:(这里是Oracle数据库)
package ling.sample.db;
import java.sql.*;
import javax.sql.*;
import java.util.UUID;
import java.io.*;
import java.util.Properties;
//DataSource
import oracle.jdbc.pool.*;
import javax.naming.Context;
import javax.naming.InitialContext;
public class DB
{
//格式为"jdbc:oracle:thin:@ip:port:dbName";
privatestatic String url = "jdbc:oracle:thin:@192.168.0.110:1521:myoracle";
privatestatic String userName = "myoracle";
privatestatic String password = "myoracle";
publicstatic final String ORACLE_DRIVER ="oracle.jdbc.driver.OracleDriver";
publicstatic Connection createConection()
{
try
{
//加载Driver
Class.forName(DB.ORACLE_DRIVER);
Connectionconnection = DriverManager.getConnection(url, userName, password);
returnconnection;
}
catch(Exceptionex)
{
System.out.println(ex.getMessage());
}
returnnull;
}
publicstatic void closeConnecion(Connection connection)
{
if(connection!= null)
{
try
{
connection.close();
}
catch(Exceptionex)
{
System.out.println(ex.getMessage());
}
}
}
publicstatic void closeStatement(Statement statement)
{
if(statement!= null)
{
try
{
statement.close();
}
catch(Exceptionex)
{
}
}
}
publicstatic void closeResultSet(ResultSet resultSet)
{
if(resultSet!= null)
{
try
{
resultSet.close();
}
catch(Exceptionex)
{
System.out.println(ex.getMessage());
}
}
}
publicstatic ResultSet executeQuery(Connection connection, String sql)
throwsSQLException
{
Statementstatement = connection.createStatement();
ResultSetresultSet = statement.executeQuery(sql);
returnresultSet;
}
publicstatic ResultSet executeQuery(String sql)
{
Connectionconnection = DB.createConection();
ResultSetresultSet = null;
try
{
resultSet= DB.executeQuery(connection, sql);
}
catch(SQLExceptionex)
{
}
finally
{
DB.closeConnecion(connection);
}
returnresultSet;
}
publicstatic boolean executeUpdate(Connection connection, String sql)
{
intresult = 0;
Statementstatement = null;
try
{
statement= connection.createStatement();
result= statement.executeUpdate(sql);
}
catch(Exceptionex)
{
}
finally
{
DB.closeStatement(statement);
}
returnresult > 0;
}
publicstatic boolean executeUpdate(String sql)
{
Connectionconnection = DB.createConection();
if(connection== null)
{
returnfalse;
}
try
{
returnDB.executeUpdate(connection, sql);
}
catch(Exceptionex)
{
}
finally
{
DB.closeConnecion(connection);
}
returnfalse;
}
/**
* 生成一个唯一的id
*/
publicstatic String createUUID()
{
returnUUID.randomUUID().toString();
}
/**
* 使用DataSource接口创建一个连接。
* 此种方式移植性更好,只需要在本机配置数据库的数据源即可。
* @return
*/
publicstatic Connection createConnectionFromDS()
{
try
{
OracleDataSourceoracelDataSource = new OracleDataSource();
oracelDataSource.setServerName("SERVER-CENTER");
//oracelDataSource.setURL("202.117.118.45");
oracelDataSource.setDatabaseName("myoracle");
Contextcontext = new InitialContext();
context.bind("jdbc/repace",oracelDataSource);
DataSourcedataSource = (DataSource) context.lookup("jdbc/myoracle");
Connectionconnection = dataSource.getConnection("myoracle","myoracle");
returnconnection;
}
catch(Exceptionex)
{
}
returnnull;
}
publicstatic void main(String[] args)
{
Connectionconnection = DB.createConection();
//Connectionconnection = DB.createConnectionFromDS();
if(connection!= null)
{
System.out.println("Connectto oralce successfully!");
}
else
{
System.out.println("Faliledto connect to oralce!");
}
}
}
为简单起见,这里所有的数据使用的是static的string私有数据及方法,这样使用时可以不必保存DB对象。
也可以将数据库的配置数据写在一个属性文件中(如何使用java读取/设置属性文件参考,如何读取环境变量参考http://ling091.javaeye.com/admin/blogs/354052)。
文件中的值如下:
IP= 192.168.0.110
port=1521
serviceName=myoracle
userName=myoracle
password=myoracle
代码如下(需要包含头文件java.util.Properties,如用Eclipse 可以使用Ctrl-Shift-O自动包含未包含的头文件,Mac上使用Cmd-Shift-O):
private staticString[] readProperties()
{
StringpropFile = DB.PROP_FILE;
//根目录保存在环境变量中
StringmuleHome = System.getenv("ORACLE_EXAMPLE_HOME");
if(dirHome != null)
{
propFile= dirHome + "//userconf//" +propFile;
}
//如果不存在配置文件
/*File file = new File(propFile);
if(!file.exists() )
{
System.out.println("找不到配置文件oracel.conf,使用程序默认配置!");
return null;
}*/
String[]properties = new String[5];
String[]propNames = {"IP", "port", "serviceName","userName", "password"};
Propertiesprops = new Properties();
InputStreamistream = null;
try
{
istream= new BufferedInputStream (new FileInputStream(propFile) );
props.load(istream);
for(inti = 0; i < propNames.length; i++)
{
properties[i]= props.getProperty (propNames[i]);
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
istream.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
return properties;
}
3 代码2 :Student类 略
4 代码3 :StudentDAO
对于有一对多,多对多的对象,DAO的实现可根据需求而定。可以每张数据表(如student表, course表)单独实现DAO,然后为关联表(student_course表)实现表征student与course关系的DAO,这意味着为每张表实现一个DAO。但如果两者关系更为密切,如表1与表2是一对多的关系,在类的层面上,表2更合适作为表1内部属性,可以将直接定义成一个对象。如联系人也可以放在学生的属性中。
这需要根据需要权衡,如同在数据库中将属性用另外的表存储还是作为已有表的属性存储,xml中作为attribute还是element是类似的。
package ling.example.oracle.dao;
import java.sql.*;
import javax.sql.*;
import java.util.*;
import example.oracle.db.*;
import example.oracle.data.*;
public class StudentDAO
{
publicstatic boolean save(Student student)
{
Stringsql = "insert into student(id, name) values(" +
+"'" + student.getID() + "',"
+"'" + student.getName() + "')";
DB.executeUpdate(sql);
}
publicstatic boolean update(Student student)
{
Stringsql = "update student set name = '"
+student.getName()
+"' where id = '"
+student.getID()
+"'";
returnDB.executeUpdate(sql);
}
publicstatic boolean deleteById(String id)
{
Stringsql = "delete from student where id = '" + id + "'";
returnDB.executeUpdate(sql);
}
publicstatic boolean deleteAll()
{
Stringsql = "delete from student”;
returnDB.executeUpdate(sql);
}
//删除满足query查询的学生
publicstatic boolean deleteByQuery(String querySQL)
{
Stringsql = "delete from student where id in (" + querySQL + “)”;
returnDB.executeUpdate(sql);
}
publicstatic List<Student> findBySQL(String sql)
{
Connectionconnection = DB.createConection();
Statementstatement = null;
ResultSetresultSet = null;
if(connection== null)
{
returnnull;
}
try
{
//ResultSetresultSet = DB.executeQuery(connection, sql);
statement= connection.createStatement();
resultSet= statement.executeQuery(sql);
List<Student>studentList = new ArrayList<Student>();
while(resultSet.next())
{
Studentstudent = new Student(
resultSet.getString(1),
resultSet.getString(2));
studentList.add(student);
}
returnstudentList;
}
catch(Exceptionex)
{
}
finally
{
DB.closeResultSet(resultSet);
DB.closeStatement(statement);
DB.closeConnecion(connection);
}
returnnull;
}
//如果有多个属性时,可以使用该查询
publicstatic List<Student> findByFiled(String fieldName, String fieldValue)
{
Stringsql = "select id, name from student where "
+fieldName
+" = '"
+fieldValue
+"'";
returnfindBySQL(sql);
}
publicstatic Student findById(String studentid)
{
List<Student>studentList = findStudentByFiled("studentid", studentid);
if(students!= null && students.length > 0)
{
returnstudentList[0];
}
returnnull;
}
publicstatic List<Student> findAll ()
{
Stringsql = "select id, name, password from student";
returnfindBySQL(sql);
}
publicstatic void main(String[] args)
{
booleanresult = false;
//--------save----------
Studentstudent = new Student( "001", "zhang san");
result= StudentDAO.saveStudent(student);
System.out.println("save:" + result);
}
}
如果有多条语句同时执行,可以使用基本的数据库操作进行:
//这里是一个复杂插入的例子,比如一个学生有多个联系人方式
//这里使用基本的数据库操作。
public static booleansaveStudent(Student student)
{
Connection connection =DB.createConection();
PreparedStatement pstatement = null;
PreparedStatement pstatement2 = null;
PreparedStatement pstatement3 = null;
if(connection == null)
{
return false;
}
try
{
connection.setAutoCommit(false);
String sql = "insert into student(id, name) values (?, ?)";
pstatement =connection.prepareStatement(sql);
String studentid =student.getID();
pstatement.setString(1, studentid);
pstatement.setString(2,student.getName() );
int result =pstatement.executeUpdate();
//插入联系人
ContractPerson[]contractPersons = student.getContractPersons();
if(contractPersons!= null && contractPersons.length > 0)
{
sql = "insert into contractPerson(id, name, phone_number)values(?, ?, ?)";
String sql3= "insert intostudent_contractPerson(id, contract_id) values(?, ?)";
pstatement2= connection.prepareStatement(sql);
pstatement3= connection.prepareStatement(sql3);
int i = 0;
int count =roles.length;
for(; i < count;++i)
{
Stringcontractid = DB.createUUID();
pstatement2.setString(1, );
pstatement2.setString(2,contractPersons[i].getName() );
pstatement2.setString(3,contractPersons[i].getPhoneNumber() );
pstatement2.executeUpdate();
pstatement2.clearParameters();
pstatement3.setString(1,studentid);
pstatement3.setString(2,contractid);
//先执行语句2 ,再执行语句3
pstatement3.executeUpdate();
pstatement3.clearParameters();
}
}
connection.commit();
return true;
}
catch(SQLException ex)
{
try
{
connection.rollback();
}
catch(Exception ex)
{
System.out.println(ex.getMessage());
}
}
finally
{
DB.closeStatement(pstatement);
DB.closeStatement(pstatement2);
DB.closeStatement(pstatement3);
DB.closeConnecion(connection);
}
return false;
}
5 参考
[hbpg] Hibernate实现分页查询的原理分析.http://www.javaeye.com/topic/261.2003.09.
如果相应的数据库定义了限定查询记录的sql语句,那么直接使用特定数据库的sql语句。如果数据库不支持分页的SQL语句,那么根据在配置文件里面
#hibernate.jdbc.use_scrollable_resultset true
默认是true,如果你不指定为false,那么Hibernate会使用JDBC2.0的scrollableresult来实现分页。如果支持scrollableresult,使用ResultSet的absolute方法直接移到查询起点,如果不支持的话,使用循环语句,rs.next一点点的移过去。
可见使用Hibernate,在进行查询分页的操作上,是具有非常大的灵活性,Hibernate会首先尝试用特定数据库的分页sql,如果没用,再尝试Scrollable,如果不行,最后采用rset.next()移动的办法。
在查询分页代码中使用Hibernate的一大好处是,既兼顾了查询分页的性能,同时又保证了代码在不同的数据库之间的可移植性。
[hbch] Hibernate 缓存机制. http://www.360doc.com/content/10/0407/10/1158044_21911705.shtml.2010.04
[dahb] 一个通用的DAO接口及Hibernate 实现.http://jayjunyu.javaeye.com/blog/215838. 2008.07.
[hbqp] Hibernate 对Dao层的处理实例. 有模糊查询和 分页. http://hi.baidu.com/xiaoxiaolq/blog/item/50c5961839488ab14bedbc70.html.2008.05.
- 数据库API的封装
- android数据库使用系统封装的api实现SQLite数据库的增删改查
- API就是用来封装的
- WIN32 API的.NET封装
- 对API的再次封装
- Java封装自己的Api
- sqlite3 api的简单封装
- MongoDB的c++封装api
- java的mysql api封装
- 数据库操作的封装
- 数据库的封装
- 连接数据库的封装
- 对数据库的封装
- 数据库类 的 封装
- 数据库类的封装
- 数据库的简单封装
- 数据库的封装包
- 数据库操作的封装
- w32.downadup.b蠕虫病毒详解及清除攻略(转)
- oracle10g在windows2003上自动备份的脚本
- wcf学习笔记3 wcf中基本概念
- 自绘CProgressCtrl进度条控件,支持自定义显示文本和进程百分比信息
- 64位ubuntu上安装ppstream
- 数据库API的封装
- google到的poi操作excel的好例子(baidu不给力啊)
- shell 字符串的截取
- 跟踪程序在Linux下的执行的函数调用
- 使用 gsoap 产生 webservice 代理类
- c/c++黑框一闪而过解决办法
- ArrayList_HashSet的比较及Hashcode分析
- AppScan 8.0
- change