一、JDBC简介
Sun公司为了简化、统一对数据库的操作,定义了一套java操作数据库的规范,称之为JDBC。
- 注意:JDBC只是一个规范,一套对数据库操作的接口,其是由sun公司定义的,所以我们在导入相关包时都是导入javaSE中的包,而不是导入相关的驱动中的包,那只是对sun公司JDBC的实现。
- JDBC主要由两个包组成:
java.sql
和javax.sql
。开发jdbc应用需要以上两个包的支持外,还需要导入相应的jdbc的数据库实现(即驱动)。而java.sql
和javax.sql
已经称为javaSE的规范,所以现在不需要导入了。只需要导入相关的驱动就可以了。
二、第一个JDBC程序
2.1搭建试验环境
- 1.在mysql中创建一个库,并创建user表和插入表的数据。
create database day14;
use day14;
create table user(
id int primary key auto_increment,
name varchar(40),
password varchar(40),
email varchar(60),
birthday date
)character set utf8 collate utf8_general_ci;
insert into user(name,password,email,birthday) values('zs','123456','zs@sina.com','1980-12-04');
insert into user(name,password,email,birthday) values('lisi','123456','lisi@sina.com','1981-12-04');
- 2.新建一个java工程(
day14
),并导入相关数据库驱动。
驱动是:mysql-connector-java-5.1.37-bin.jar
Demo1.java
package cn.itcast.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Demo1 {
public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://localhost:3305/day14";
String username = "root";
String password = "walp1314";
//1.加载驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//2.获取与数据库的链接
Connection connection = DriverManager.getConnection(url, username, password);
//3.获取用于向数据库发送sql语句的statement对象
Statement st = connection.createStatement();
//4.向数据库发送sql语句,并获取代表结果集的ResultSet对象
String sql = "select id, name, password, email, birthday from user";
ResultSet result = st.executeQuery(sql);
//5.取出结果集的数据
while(result.next()){
System.out.println("id= " + result.getObject("id"));
System.out.println("name= " + result.getObject("name"));
}
//6.关闭链接,释放资源
result.close();
st.close();
connection.close();
}
}
2.2程序详解
2.2.1 DriverManager
- jdbc程序中的
DriverManager
用于加载驱动,并创建与数据库的连接,这个API的常用方法:
DriverManager.registerDriver(new Driver());
DriverManager.getConnection(url,user,password);
- 注意:在实际开发中并不推荐采用
registerDriver
方法注册驱动。原因有二:
一是通过Driver的源代码可以看到,如果采用此种方式,会导致驱动程序注册两次,也就是在内存中会有两个Driver对象。
二是程序依赖mysql的api,脱离这个api的jar包,程序将无法编译,这样不便于切换底层数据库。
推荐方式:Class.forName("com.mysql.jdbc.Driver");
采用此种方式不会导致驱动对象在内存中重复出现,并且采用此种方式,程序仅仅需要一个字符串,不需要依赖具体的驱动,程序的灵活性更高。
同样也不建议采用具体的驱动类型指向getConnection
方法返回的connection
对象,比如:
conn = (com.mysql.jdbc.Connection) DriverManager.getConnection(url, username, password);
2.2.2 数据库URL
- url用于标识数据库的位置,程序员通过url地址告诉jdbc程序连接哪个数据库,url的写法为:
jdbc:mysql://localhost:3305/day14?参数名:参数值
问号后面可以带上编码信息,如果不带,则根据数据库的编码自动指定。 - 常用数据库URL地址的写法:
Oracle写法:jdbc:oracle:thin:@localhost:1521:sid
SqlServer写法:jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=sid
MySql写法:jdbc:mysql://localhost:3305/day14
- 常用属性:
useUnicode=true&characterEncoding=UTF-8
2.2.3 Connection
- jdbc程序中的
Connection
用于代表数据库的连接,Connection
是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过Connection
对象完成的,这个对象的常用方法:
createStatement()
:创建向数据库发送sql的statement对象。
prepareStatement(sql)
:创建向数据库发送预编译sql的PrepareSatement对象。
prepareCall(sql)
:创建执行存储过程的callableStatement对象。
setAutoCommit(boolean autoCommit)
:设置事务是否自动提交。
commit()
:在链接上提交事务。
rollback()
:在此链接上回滚事务。
2.2.4 Statement
- jdbc程序中的Statement对象用于向数据库发送sql语句,Statement对象常用方法:
executeQuery(String sql)
:用于向数据发送查询语句。
executeUpdate(String sql)
:用于向数据库发送insert、update或delete语句
execute(String sql)
:用于向数据库发送任意sql语句
addBatch(String sql)
:把多条sql语句放到一个批处理中。
executeBatch()
:向数据库发送一批sql语句执行。 - 注意:这个addBatch是先将多条语句添加到Statement对象中,然后使用executeBatch方法一起执行。
2.2.5 ResultSet
- jdbc程序中的ResultSet用于代表sql语句的执行结果。ResultSet封装执行结果时,采用的类似于表格的方式。ResultSet对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用
ResultSet.next()
方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。 - ResultSet既然是用于封装执行结果的,所以该对象提供的都是用于获取数据的get方法:
获取任意类型的数据
getObject(int index)
getObject(string columnName)
获取指定类型的数据
getString(int index)
getString(String columnName)
- 提问:数据库中列的类型是varchar,获取该列的数据调用什么方法?int类型呢?bigint类型呢?Boolean类型?
常用数据类型转换表
sql类型 | jdbc对应的方法 | 返回类型 |
---|---|---|
BIT(1) BIT(N) | getBoolean getBytes() | boolean byte[] |
TINYINT | getByte() | byte |
SMALLINT | getShort() | short |
INT | getInt() | int |
BIGINT | getLong() | long |
CHAR,VARCHAR,LONGVARCHAR | getString() | String |
TEXT(clob) BLOB | getClob() getBlob() | Clob Blob |
DATE | getDate() | java.sql.Date |
TIME | getTime() | java.sql.Time |
TIMESTAMP | getTimestamp() | java.sql.Timestamp |
- ResultSet还提供了对结果进行滚动的方法:
next()
:移动到下一行
previous()
:移动到前一行
absolute(int row)
:移动到指定行
beforeFirst()
:移动resultSet的最前面。
afterLast()
:移动到resultSet的最后面。
注意:开始时指向表头,使用一次next才指向第一条数据,而使用afterLast方法之后指向表尾,这样使用previous方法才执行最后一条数据。
2.2.6 释放资源
- jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet、Statement和Connection对象。
- 特别是Connection对象,它是非常稀有的资源,用完后必须马上释放,如果不能及时、正确的关闭,很容易导致宕机。其使用原则是尽量晚创建,尽量早的释放。
- 为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。
对上面例子进行修正:Demo.java
package cn.itcast.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Demo2 {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
String url = "jdbc:mysql://localhost:3305/day14";
String username = "root";
String password = "walp1314";
Connection connection = null;
Statement statement = null;
ResultSet result = null;
try{
//1.加载驱动(推荐)
Class.forName("com.mysql.jdbc.Driver");
//2.获取与数据库的链接
connection = DriverManager.getConnection(url, username, password);
//3.获取用于向数据库发送sql语句的statement对象
statement = connection.createStatement();
//4.向数据库发送sql语句,并获取代表结果集的ResultSet对象
String sql = "select id, name, password, email, birthday from user";
result = statement.executeQuery(sql);
//5.取出结果集的数据
while(result.next()){
System.out.println("id= " + result.getObject("id"));
System.out.println("name= " + result.getObject("name"));
}
}finally{
//6.关闭链接,释放资源
//方式一:
/*if(result != null){
try {
result.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}*/
//方式二:
if(result != null){
try {
result.close();
} catch (Exception e) {
e.printStackTrace();
}finally{
if(statement != null){
try {
statement.close();
} catch (Exception e) {
e.printStackTrace();
}finally{
if(connection != null){
try {
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}
}
}
说明:
- 我们在使用jdbc的时候必须要保证最后资源能够释放,不管前面程序是否运行正确。于是我们将资源释放的代码放在finally块中,这样就保证了不管发生什么情况下资源都会被释放。上面我们提供了两种释放资源的方式,因为每一个关闭语句都可能会产生异常,所以关闭比较麻烦。
- finally块中的语句在JVM(exit(1))或是死循环时是不会执行的,其他情况下都会执行,同时注意是在return语句之前执行。
三、使用JDBC对数据库进行CRUD
从之前的例子中我们可以发现在每次使用数据库都需要链接数据库和释放资源,我们可以将这些重复的代码统一放在一个工具类中。同时对于数据库中需要用到的一些资源,比如url、用户名、密码等我们直接写死在程序中也不便于日后维护,于是我们将这些资源放在一个配置文件中。
src/db.properties
### MySQL
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3305/day14
username=root
password=walp1314
### Oracle
#driver=oracle.jdbc.driver.OracleDriver
#url=jdbc:oracle:thin:@localhost:1521:orcl
#username=root
#password=walp1314
JdbcUtils.java
package cn.itcast.utils;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JdbcUtils {
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null;
static {
try{
//获取资源文件,这里我们的资源文件放在src下
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
Class.forName(driver);
}catch(Exception e){
throw new ExceptionInInitializerError(e);
}
}
//获得数据库链接
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection(url, username, password);
}
//释放资源
public static void release(Connection conn, Statement st, ResultSet rs){
if(rs != null){
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(st != null){
try {
st.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
测试:Demo3.java
package cn.itcast.demo;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import org.junit.Test;
import cn.itcast.utils.JdbcUtils;
public class Demo3 {
//数据库插入
@Test
public void insert(){
Connection connection = null;
Statement statement = null;
ResultSet result = null;
try {
//通过工具类获得数据库的链接
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
String sql = "insert into user(id, name, password, email, birthday) "
+ "values(4, 'xxx', '12', 'xx@sina.com', '1998-09-09')";
//下面的返回值表示影响了数据库多少行
int num = statement.executeUpdate(sql);
if(num > 0){
System.out.println("插入成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//通过工具类释放资源
JdbcUtils.release(connection, statement, result);
}
}
//删除操作
@Test
public void delete(){
Connection connection = null;
Statement statement = null;
ResultSet result = null;
try {
//通过工具类获得数据库的链接
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
String sql = "delete from user where id = 4";
int num = statement.executeUpdate(sql);
if(num > 0){
System.out.println("删除成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//通过工具类释放资源
JdbcUtils.release(connection, statement, result);
}
}
//修改操作
@Test
public void update(){
Connection connection = null;
Statement statement = null;
ResultSet result = null;
try {
//通过工具类获得数据库的链接
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
String sql = "update user set name='tom', email='tom@sina.com' where id = 2";
int num = statement.executeUpdate(sql);
if(num > 0){
System.out.println("修改成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//通过工具类释放资源
JdbcUtils.release(connection, statement, result);
}
}
//查找操作
@Test
public void find(){
Connection connection = null;
Statement statement = null;
ResultSet result = null;
try {
//通过工具类获得数据库的链接
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
String sql = "select * from user where id = 1";
result = statement.executeQuery(sql);
if(result.next()){
System.out.println(result.getString("name"));
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//通过工具类释放资源
JdbcUtils.release(connection, statement, result);
}
}
}
注意:在以后的开发中我们不会再使用Statement这个对象,而是使用其子类PreparedStatement,同时这个对象可以防范sql注入,相关使用方法请看笔记17.2 。