您的位置:首页 > 其它

JDBC 快速入门

2010-02-06 16:38 281 查看
  1年多没碰JDBC了,原来就没怎么学,现在稍微系统的复习以下:

JDBC的架构:



此图是O'Reilly的书摘里面您的,还是2.0时代的东西,我主要参考官方文档里面的内容,JDBC现在3.0

JDBC的介绍是这样的:

The Java Database Connectivity (JDBC) API provides universal data access from the Java programming language. Using the JDBC 3.0 API, you can access virtually any data source, from relational databases to spreadsheets and flat files. JDBC technology also provides a common base on which tools and alternate interfaces can be built.

JDBC API提供一种从Java的通用型/泛用型数据访问方法.使用JDBC3.0的API你可以访问任何数据源,从关系型数据库到电子表格到普通的文件.JDBC也提供了其他工具和接口构建的共同基础.

JDBC主要在两个包里面:

java.sql

javax.sql

  后者附带了服务器端的一些功能

JDBC的链接过程

  典型的过程是加载驱动->建立连接

  JDBC通常有两种方式:

DriverManager:这种是直接和数据库链接

DataSource:这种通过数据库连接池来连接的,这个池的概念比较不错.而且,通常当你不用的时候,链接是返回到池里面的,并不会断开连接,这样的频繁的访问的情况下,就不要花费大连的时间来建立和断开连接了.

package JDBCPractice;
import java.sql.*;
import javax.naming.InitialContext;
import javax.sql.*;
public class main {
/**
* @param args
*/
public static void main(String[] args) {

//-----------------------Using the DriverManager Class-------------------------

try {
Class.forName("com.mysql.jdbc.Driver");
//建立一个mysql的driver的实例,并将其注册到DriversManager
//注意的是,这样已经自动创建了实例了,不需要再建一个.
//DriverManager会自动维护可用的驱动集合,所以
//你只要提供一个URL,它就乎自动找到驱动并去连接

} catch (ClassNotFoundException e) {
System.out.println("Unable load Driver");
e.printStackTrace();
}

String name = "root";
String password = "moratorium";
String url = "jdbc:mysql://localhost/JavaPricticeDB";
//jdbc:mysql://[host][,failoverhost...][:port]/[database] »
//[?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]...
//默认host没有指定是127.0.0.1,port没有是3306
//如果database没有指定的话,就没有默认的数据库,这个时候必须要使用
//set-Catalog()方法或者对表名使用完整的数据库名称引用。
//文档上说这种连接方法通常只是在你的工具用来管好多个数据库的时候有用。
try {
Connection con = DriverManager.getConnection(url, name, password);
Statement ste = con.createStatement();
ResultSet rs = ste.executeQuery("select * from dmt");
System.out.println("print dm sel res");
while(rs.next()) {
System.out.println( "" + rs.getInt(1) + "/t" +	rs.getString(2));
}
System.out.println("--------------------------");
} catch (SQLException e) {
System.out.println("Errors occuored while connecting to the database:/t"+ url);
e.printStackTrace();
}

//------------------------------------------------------------------------

//---------------Using a DataSource Object for a connection-----------------
//使用DataSource对象来连接数据库应该更加符合OO的思想,你无须关心连接的数据库的
//对象是什么。它对你来说是透明的
/*InitialContext ic = new InitialContext();

DataSource ds = ic.lookup("java:comp/env/jdbc/myDB");
Connection con = ds.getConnection();
DataSource ds = (DataSource) org.apache.derby.jdbc.ClientDataSource()
ds.setPort(1527);
ds.setHost("localhost");
ds.setUser("APP")
ds.setPassword("APP");

Connection con = ds.getConnection(); */
//上面这段是官方教程上给的说明,不过实际上,如果你需要是用DataSource连接的话还需要使用JNDI,
//Mysql的文档上说明的例子是spring, tomcat, J2EE Server。这里我是跑不了了。

}
}


结果集的处理:

  ResultSet接口提供了获取和操作执行结果的方法。ResultSet通过两个设置来决定它的机能,一个是游标的可操作方法,另外一个ResultSet的改变是如何影响到底层的数据源的。

  有三种不同的ResultSet类型:

TYPE_FORWARD_ONLY
,这个类型游标只能往前移动

TYPE_SCROLL_INSENSITIVE
,游标可以前后移,还可以跳到一个绝对位置

YPE_SCROLL_SENSITIVE,同上,不知道是不是有错

  ResultSet中控制游标:

next():向后移动一行,当在一行中时返回true,当在最后一行之后返回false


previous()
:向前一行,同理当在第一行之前返回false

first()
- 移动到ResultSet的第一行,当为空是返回false

last()
- 同理

beforeFirst()
- 移到第一行之前,当为空时此方法没有作用

afterLast()
- 同理

relative(int rows)
- 跳到相对当前行的位置,relative(-3),从现在往前倒3行,比如现在是第四行,往前倒到第一行

absolute(int row)
- 跳到第row行,当为负数是从最后一行开始数起,比如有500行,absolute(-4)就是第497行

  获得数据:

  每个字段的数据都可以用getXXX方法获得,不过指导里面说应该从左往右读,而且每个仅读一次,而且最好用字段索引(从1开始i),因为字段名可以相同,此时只会获得第一个对应的字段。

  注意getINT可以用来读INTEGER,
BINARY
,
VARBINARY
,
LONGVARBINARY
,
DATE
,
TIME
, or
TIMESTAMP
.

  更新数据:

  update需要两步:先更新字段,之后在应用到对应的行,此时才会写入到底层的数据源

Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
//TYPE_FORWARD_ONLY, TYPE_SCROLL_INSENSITIVE, and TYPE_SCROLL_SENSITIVE.分别对应三种类型
//CONCUR_READ_ONLY and CONCUR_UPDATABLE,定义ResultSet只是可读还是可更新
ResultSet upr = stmt.executeQuery("SELECT keyc, valuec FROM dmt");
upr.updateString(2, "nothing");
//修改第一行的valuec的值为nothing
upr.updateRow();
//只有执行这一句才能真正的更新数据


插入和删除

  一般来说,既然都用Java写了,绝大多数情况下也无须去写sql来插入删除。所以JDBC可以直接做到这一点。实际上,当你获得了一个ResultSet的时候。就可以插入和删除了。在每个ResultSet里面有一个特别的行叫插入行,你可以把游标移动到这里来猛插数据。。。

System.out.println("--------------------------");
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
//TYPE_FORWARD_ONLY, TYPE_SCROLL_INSENSITIVE, and TYPE_SCROLL_SENSITIVE.分别对应三种类型
//CONCUR_READ_ONLY and CONCUR_UPDATABLE,定义ResultSet只是可读还是可更新
ResultSet upr = stmt.executeQuery("SELECT keyc, valuec FROM dmt");
upr.last();
upr.updateString(2, "nothing");

//修改最后一行的valuec的值为nothing,需要注意的是,这里upr一开始是在第一行之前的
upr.updateRow();
//只有执行这一句才能真正的更新数据
//----------------插入也用一样的ResultSet,所以无须毁掉--------------------
upr.moveToInsertRow();
upr.updateInt(1, 3);
upr.updateString(2,"NNNN");
upr.insertRow();
//打完收工
//需要注意的是,如果你某个字段有默认值,你不赋值是可以的,但是如果没有。你有没赋值,那就赏你一个SQLException

upr.absolute(1);
upr.deleteRow();
//delete最简单了。移到位置,del即可

upr.close();
stmt.close();
con.close();


预编译语句:

  如果你常用一个语句的话,可以用预编译语句来优化它。这样使得送出的查询无须翻译,直接可以执行。

PreparedStatement updateSales = con.prepareStatement(
"UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
//两个问号就是占位符,在下面分别用1,2来索引
updateSales.setInt(1, 75);
updateSales.setString(2, "Colombian");
updateSales.executeUpdate():
//上面一段代码在SQL的查询上等效于这个:
String updateString = "UPDATE COFFEES SET SALES = 75 " +
"WHERE COF_NAME LIKE 'Colombian'";
stmt.executeUpdate(updateString);


使用Transactions:

  不知道正规的名称是不是叫事务,反正一个Transactions 就是一组语句,要么都跑完,要么都不跑。

  默认,建立一个连接的时候它是在auto-commit模式下的,也就是自动提交模式,这个时候每个语句被当成一个事务,并且一执行完就自动提交。

con.setAutoCommit(false);
//关闭auto-commit模式
PreparedStatement updateSales = con.prepareStatement(
"UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?");
updateSales.setInt(1, 50);
updateSales.setString(2, "Colombian");
updateSales.executeUpdate();
PreparedStatement updateTotal = con.prepareStatement(
"UPDATE COFFEES SET TOTAL = TOTAL + ? WHERE COF_NAME LIKE ?");
updateTotal.setInt(1, 50);
updateTotal.setString(2, "Colombian");
updateTotal.executeUpdate();
con.commit();
//提交
con.setAutoCommit(true);
//恢复auto-commit


  此外,还可以设置一个回滚保存点:

tatement stmt = conn.createStatement();
int rows = stmt.executeUpdate("INSERT INTO TAB1 (COL1) VALUES " +
"(?FIRST?)");
// 设置保存点
Savepoint svpt1 = conn.setSavepoint("SAVEPOINT_1");
rows = stmt.executeUpdate("INSERT INTO TAB1 (COL1) " +
"VALUES (?SECOND?)");
...
conn.rollback(svpt1);
//这一句跑完之后,从上面那


  一般来说,要rollback通常还是在一个transcations里面遇到了SQLException的时候。

附加:使用批量更新batch updates

  一条一条update效率不比一次发送很多条update语句高(其实也可以是delete和insert),所以有了这个batch update

con.setAutoCommit(false);
Statement stmt = con.createStatement();

stmt.addBatch("INSERT INTO COFFEES " +
"VALUES('Amaretto', 49, 9.99, 0, 0)");
stmt.addBatch("INSERT INTO COFFEES " +
"VALUES('Hazelnut', 49, 9.99, 0, 0)");
stmt.addBatch("INSERT INTO COFFEES " +
"VALUES('Amaretto_decaf', 49,
10.99, 0, 0)");
stmt.addBatch("INSERT INTO COFFEES " +
"VALUES('Hazelnut_decaf', 49,
10.99, 0, 0)");
int [] updateCounts = stmt.executeBatch();
con.commit();
con.setAutoCommit(true);
//-----------------参数化的做法--------------------
con.setAutoCommit(false);
PreparedStatement pstmt = con.prepareStatement(
"INSERT INTO COFFEES VALUES(
?, ?, ?, ?, ?)");
pstmt.setString(1, "Amaretto");
pstmt.setInt(2, 49);
pstmt.setFloat(3, 9.99);
pstmt.setInt(4, 0);
pstmt.setInt(5, 0);
pstmt.addBatch();

pstmt.setString(1, "Hazelnut");
pstmt.setInt(2, 49);
pstmt.setFloat(3, 9.99);
pstmt.setInt(4, 0);
pstmt.setInt(5, 0);
pstmt.addBatch();

// ... and so on for each new type of coffee

int [] updateCounts = pstmt.executeBatch();
con.commit();
con.setAutoCommit(true);
//最后注意的是,只有这些语句可以跑,千万不要在这里跑select
//INSERT INTO, UPDATE, DELETE or that return 0 such as CREATE TABLE, DROP TABLE, ALTER TABLE
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: