jisonami A Java Dev Engineer

Java的jdbc编程步骤

2016-04-06

JDBC编程的步骤有以下几步:

1、 加载JDBC驱动,利用Java的反射机制

2、 通过DriverManager获取数据库连接,即调用静态工厂方法创建Connection对象

3、 通过Connection对象创建Statement对象

4、 执行SQL语句

5、 操作SQL语句返回的结果集

6、 关闭数据库资源

下面详细说明每一步的具体操作。

加载JDBC驱动,利用Java的反射机制

Class.forName(“数据库厂商提供的JDBC驱动的Driver全限定类名”);

Oracle数据库驱动的Driver全限定类名为“oracle.jdbc.driver.OracleDriver”

MySQL数据库驱动的Driver全限定类名为“com.mysql.jdbc.Driver”

通过DriverManager获取数据库连接

即调用静态工厂方法创建Connection对象

DriverManager类提供了三个重载的静态工厂方法可以创建Connection对象

Connection getConnection(String url) 
Connection getConnection(String url, Properties info) 
Connection getConnection(String url, String user, String password) 

MySQL的url写法如下:

jdbc:mysql://hostname:port/databasename 

Oracle的url写法如下:

jdbc:oracle:thin:@hostname:port:databasename 

通过Connection对象创建Statement对象

Connection类提供了创建三种类型Statement对象的实例工厂方法,每种类型的方法均有几个参数不同的重载方法。

// 创建Statement 对象,Statement接口提供基本执行SQL语句的能力。 
Statement createStatement() 
// 创建PreparedStatement对象,PreparedStatement接口继承了Statement接口,提供SQL语句接受输入参数的能力。 
PreparedStatement prepareStatement(String sql) 
// 创建CallableStatement对象,CallableStatement接口继承了PreparedStatement接口,提供执行存储过程的能力。 
CallableStatement prepareCall(String sql) 

一般来说,总是选择PreparedStatement而不是Statement执行SQL语句,因为PreparedStatement可以有效的防止SQL注入

执行SQL语句

Statement类提供了执行SQL语句的三种类型的方法。

// 可执行任意SQL语句,并返回是否执行成功,该方法有多个重载方法。 
boolean execute(String sql) 
// 可执行SQL查询语句,并返回查询结果集。 
ResultSet executeQuery(String sql) 
// 执行给定 SQL 语句,当该语句为 INSERT、UPDATE 或 DELETE 语句时,返回SQL语句改变行数,当该语句为SQL DDL 语句,返回0。该方法有多个重载方法。 
int executeUpdate(String sql) 

操作SQL语句返回的结果集

第4步中执行SQL查询语句时获得的ResultSet对象有两种类型的方法。

1) 移动ResultSet记录指针的方法

// 将光标移动到此 ResultSet 对象的给定行编号。 
boolean absolute(int row) 
// 将光标移动到此 ResultSet 对象的末尾,正好位于最后一行之后。 
void afterLast() 
// 将光标移动到此 ResultSet 对象的开头,正好位于第一行之前。 
void beforeFirst() 
// 将光标移动到此 ResultSet 对象的第一行。 
boolean first() 
// 将光标移动到此 ResultSet 对象的最后一行。 
boolean last() 
// 将光标从当前位置向前移一行。 
boolean next() 
// 将光标移动到此 ResultSet 对象的上一行。 
boolean previous() 

2) 获取当前记录指针指定列的方法

// 根据指定第columnIndex列获取当前记录指针行对应的值 
getXXX(int columnIndex) 
// 根据指定columnIndex列名获取当前记录指针对应的值 
getXXX(String columnName) 

存储过程调用

Java调用存储过程时,比如procedure_demo(IN id int(11), OUT student_name varchar(255))这个存储过程

我们首先得到一个Connection对象,一般是从数据库连接池中获取

接着

CallableStatement cstat = conn.prepareCall("{call procedure_demo(?, ?)}");  

得到一个CallableStatement对象

这里使用了?作为参数占位符

设置输入参数

cstat.setInt(1, 1);  

设置输出参数的类型

cstat.registerOutParameter(2, Types.VARCHAR);  

调用存储过程

cstst.execute();  

获取存储过程输出参数返回值

cstst.getString(2);

关闭数据库资源

关闭数据库资源分为三步,调用ResultSet、Statement和Connection对应的close()方法

1) 若执行了SQL查询语句,需要关闭ResultSet对象(不是查询语句没有打开ResultSet则没有此步骤)

2) 关闭Statement对象

3) 关闭Connection对象

以上步骤用UML图表示如下(图片来源于网络)

JDBC UML图表示

下面按照这些步骤实现JDBC编程,以Oracle为例

安装oracle11gR2参考:

Redhat/CentOS下安装Oracle11gR2记录

win-server2008-r2安装oracle11gR2

oracle11gR2创建用户和表空间记录

现在假设有一个t_user的表,假设我们的连接数据库的信息如下:

driver=oracle.jdbc.driver.OracleDriver  
url=jdbc:oracle:thin:@192.168.75.130:1521:orcl  
user=jison  
pass=jison  

我们的业务逻辑是要注册一个用户,那么,我们可以这样写这样一个方法

public boolean save(User user) throws SQLException{  
                String id = UUID.randomUUID().toString().replace("-", "")  
    user.setId(id);  
    String driver = "oracle.jdbc.driver.OracleDriver";  
    String url = "jdbc:oracle:thin:@192.168.75.130:1521:orcl";  
    String user = "jison";  
    String pass = "jison";  
    Class.forName(driver);  
    Connection conn = DriverManager.getConnection(url, user, pass);  
    String sql = "insert into t_user(id, name, password) values(?, ?, ?)";  
    PreparedStatement preStmt = conn.prepareStatement(sql);  
    preStmt.setString(1, user.getId());  
    preStmt.setString(2, user.getName());  
    preStmt.setString(3, user.getPassword());  
    int rowChange = preStmt.executeUpdate();  
    preStmt.close();  
    conn.close();  
    if(rowChange != 0){  
        return true;  
    }  
    return false;  
}  

上面用到一个User类

public class User {  
    private String id;  
    private String name;  
    private String password;  
      
    public String getId() {  
        return id;  
    }  
    public void setId(String id) {  
        this.id = id;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public String getPassword() {  
        return password;  
    }  
    public void setPassword(String password) {  
        this.password = password;  
    }  
      
}  

对于上面的配置信息,我们可以简单的封装在一个Java的Properties文件,而连接数据库时因为加载驱动只需要进行一次,那么我们将其移到静态代码块里。修改后的代码如下:

DBConfig.properties代码

driver=oracle.jdbc.driver.OracleDriver  
url=jdbc:oracle:thin:@192.168.75.130:1521:orcl  
user=jison  
pass=jison  
import java.sql.Connection;  
import java.sql.PreparedStatement;  
import java.sql.ResultSet;  
import java.sql.SQLException;  
import java.util.UUID;  
  
import org.jisonami.entity.User;  
import org.jisonami.sql.DBUtils;  
  
public class UserService {  
static Properties properties = new Properties();  
    static {  
        try {  
            properties.load(UserService .class.getClassLoader().getResourceAsStream("DBConfig.properties"));  
            Class.forName(properties.getProperty("driver"));  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
      
    public static Connection getConnection() throws SQLException{  
        return DriverManager.getConnection(properties.getProperty("url"),   
                properties.getProperty("user"),  
                properties.getProperty("pass"));  
    }  
    public boolean save(User user) throws SQLException{  
        user.setId(generateId());  
        Connection conn = UserService.getConnection();  
        String sql = "insert into t_user(id, name, password) values(?, ?, ?)";  
        PreparedStatement preStmt = conn.prepareStatement(sql);  
        preStmt.setString(1, user.getId());  
        preStmt.setString(2, user.getName());  
        preStmt.setString(3, user.getPassword());  
        int rowChange = preStmt.executeUpdate();  
        preStmt.close();  
        conn.close();  
        if(rowChange != 0){  
            return true;  
        }  
        return false;  
    }  
    private static String generateId(){  
        return UUID.randomUUID().toString().replace("-", "");  
    }  
}  

DataSource数据源

前面的数据库连接都是使用DriverManager.getConnection()的方式获取数据库连接的,这样每次执行sql语句都重新打开一个新的数据库连接,执行完sql语句后有关闭掉比较消耗性能。

于是jdbc就有了DataSource数据连接池的概念,数据源的配置与前面是一样的,必须的配置有四个jdbc驱动类名、数据库url、用户名、密码。

jdbc只提供了DataSource接口,不同的数据源实现中这四个参数的名字不完全一样。

开源的数据连接池池有apache的dpcp数据库连接池,hibernate使用的c3p0数据库连接池。

dpcp有两个版本,分别是commons-dpcp和commons-dpcp2,我们就使用commons-dpcp2好了。 org.apache.commons.dbcp2.BasicDataSource是commons-dpcp2对DataSource接口的实现,直接实例化该对象,并将数据库连接信息set到该对象即可。

BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(DBUtils.getDriver());
dataSource.setUrl(DBUtils.getUrl());
dataSource.setUsername(DBUtils.getUserName());
dataSource.setPassword(DBUtils.getPassword());

com.mchange.v2.c3p0.ComboPooledDataSource是c3p0对DataSource接口的实现,直接实例化该对象,并将数据库连接信息set到该对象即可。

ComboPooledDataSource datasource = new ComboPooledDataSource();
datasource.setDriverClass(DBUtils.getDriver());
datasource.setJdbcUrl(DBUtils.getUrl());
datasource.setUser(DBUtils.getUserName());
datasource.setPassword(DBUtils.getPassword());

上面的DBUtils工具类用于提取DBConfig.properties的配置信息,代码如下

public class DBUtils {
	static Properties properties = new Properties();
	static {
		try {
			properties.load(DBUtils.class.getClassLoader().getResourceAsStream("DBConfig.properties"));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static String getDriver(){
		return properties.getProperty("driver");
	}
	
	public static String getUrl(){
		return properties.getProperty("url");
	}
	
	public static String getUserName(){
		return properties.getProperty("user");
	}
	
	public static String getPassword(){
		return properties.getProperty("pass");
	}
}

如果是使用了Spring这类依赖注入的框架的话,就可以直接将数据源的实例化配置在配置文件里面了,就不需要直接new对象了。

得到DataSource对象之后,就可以用DataSource获取Connection了

datasource.getConnection();

DataSource得到的Connection做完相应的数据库操作之后,直接像正常的调用close()方法即可,这个操作不会关闭数据库连接,而是将该连接重新初始化后等待新的获取连接请求。


Similar Posts

上一篇 Java的反射

Comments