JDBC是连接数据库和Java程序的桥梁,通过JDBC API可以方便地实现对各种主流数据库的操作。本篇将介绍一下如何使用JDBC操作数据库(以MySQL为例)。
一、JDBC
JDBC制定了统一访问各类关系数据库的标准接口,为各个数据库厂商提供了标准接口的实现。
JDBC规范将驱动程序归结为以下几类(选自Core Java Volume Ⅱ——Advanced Features):
- 第一类驱动程序将JDBC翻译成ODBC,然后使用一个ODBC驱动程序与数据库进行通信。
- 第二类驱动程序是由部分Java程序和部分本地代码组成的,用于与数据库的客户端API进行通信。
- 第三类驱动程序是纯Java客户端类库,它使用一种与具体数据库无关的协议将数据库请求发送给服务器构件,然后该构件再将数据库请求翻译成数据库相关的协议。
- 第四类驱动程序是纯Java类库,它将JDBC请求直接翻译成数据库相关的协议。
二、通过JDBC操作数据库
我们需要访问数据库时,首先要加载数据库驱动,只需加载一次,然后在每次访问数据库时创建一个Connection实例,获取数据库连接,获取连接后,执行需要的SQL语句,最后完成数据库操作时释放与数据库间的连接。
1. 加载数据库驱动
Java加载数据库驱动的方法是调用Class类的静态方法forName(),语法格式如下:
Class.forName(String driverManager)
例如加载MySQL数据库驱动如下:
try {
Class.forName("com.mysql.jdbc.Driver");
} catch(ClassNotFoundException e) {
e.printStackTrace();
}
如果加载成功,会将加载的驱动类注册给DriverManager;如果加载失败,会抛出ClassNotFoundException异常。
需要注意的是,要在项目中导入mysq-connection-java的jar包,方法是在项目中建立lib目录,在其下放入jar包。
右键jar包 Build Path->Add to Build Path。
之后会多出一个Referenced Libraries,导入成功。
2. 建立连接
加载完数据库驱动后,就可以建立数据库的连接了,需要使用DriverManager类的静态方法getConnection()方法来实现。如下:
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/database_name";
String user = "root";
Strign password = "root"
//建立连接
Connection conn = DriverManager.getConnection(url, user, password);
url是数据库的url,其中mysql指定数据库为mysql数据库,localhost是本地计算机,可以换成IP地址127.0.0.1,3306为MySQL数据库的默认端口号,database_name是所要连接的数据库名;user和password对应数据库的用户名和密码;最后再通过getConnection建立连接。
3. 对数据库表中数据进行增删改查
建立了连接之后,就可以使用Connection接口的createStatement()方法来获取Statement对象,也可以调用prepareStatement()方法获得PrepareStatement对象,通过executeUpdate()方法来执行SQL语句。
先看一个查询的。
1 import java.sql.Statement;
2 import java.sql.Connection;
3 import java.sql.DriverManager;
4 import java.sql.ResultSet;
5 import java.sql.SQLException;
6
7 public class JDBCTest {
8
9 public static void main(String[] args) throws ClassNotFoundException, SQLException {
10 //连接数据库
11 Class.forName("com.mysql.jdbc.Driver");
12 String url = "jdbc:mysql://127.0.0.1:3306/mybatis_test";
13 String user = "root";
14 String password = "123456";
15
16 //建立数据库连接
17 Connection conn = DriverManager.getConnection(url, user, password);
18
19 String sql = "select * from user";
20 Statement stmt = conn.createStatement(); //创建一个statement对象
21 ResultSet rs = stmt.executeQuery(sql); //执行查询
22
23 int id, sex;
24 String username, address;
25 System.out.println("id\t姓名\t性别\t地址\t");
26
27 while(rs.next()) { //遍历结果集
28 id = rs.getInt("id");
29 username = rs.getString("username");
30 sex = rs.getInt("sex");
31 address = rs.getString("address");
32 System.out.println(id + "\t" + username + "\t" + sex + "\t" + address);
33 }
34 }
35
36 }
运行结果如下:
一般在数据库中我们将性别写为数字,然后用Java语言进行转换,比如上述运行结果,1代表男性、2代表女性、0代表未知,我们修改sex = rs.getInt("sex");这行代码如下:
sex = rs.getInt("sex");
if(sex == 1) {
_sex = "男";
} else if(sex == 2) {
_sex = "女";
} else {
_sex = "未知";
}
首先在while循环的外面加上String _sex,在输出中将sex改为_sex即可,运行结果如下:
对于插入,我们可以使用Statement接口中的executeUpdate()方法,如下:
String sql = "insert into user(username, sex, address) values('张三','1','陕西西安')";
Statement stmt = conn.createStatement(); //创建一个Statement对象
stms.executeUpdate(sql); //执行SQL语句
conn.close(); //关闭数据库连接对象
还可以使用PreparedStatement接口中的executeUpdate()方法,如下:
String sql = "insert into user(username, sex, address) values(?,?,?)";
PreparedStatement ps = conn.preparedStatement(sql);
ps.setString(1, "张三"); //为第一个问号赋值
ps.setInt(2, 2); //为第二个问号赋值
ps.setString(3, "陕西西安"); //为第三个问号赋值
ps.executeUpdate();
conn.close();
修改同插入,也有上述两种方法,只需更改sql语句即可。
删除也是一个很常用的操作,使用executeUpdate()方法执行用来做删除的SQL语句,方法同上方Statement接口的操作。
三、完整实例
下面给一个完整的例子,该例子的数据库配置文件在外部的properties中,该例子以SQL Server为例,其它的数据库都是同样的道理。
1. jdbc.properties
用于编写数据库配置文件,不直接写在程序中的好处是提高了灵活性,如果需要修改数据库名称或配置等信息,可以在这里修改,无需改动程序。
1 driver = com.microsoft.sqlserver.jdbc.SQLServerDriver
2 url = jdbc:sqlserver://127.0.0.1:1433;DatabaseName=TTMS
3 username = root
4 password = root
2. DBUtils.java
编写JDBC代码。
1 import java.io.*;
2 import java.sql.Connection;
3 import java.sql.DriverManager;
4 import java.sql.PreparedStatement;
5 import java.sql.ResultSet;
6 import java.sql.SQLException;
7 import java.sql.Statement;
8 import java.util.Properties;
9
10 public class DBUtil {
11 private final String dbConnFile = "resource/database/jdbc.properties";
12 private Connection conn=null;
13 private String dbDriver; //定义驱动
14 private String dbURL; //定义URL
15 private String userName; //定义用户名
16 private String password; //定义密码
17
18 //从配置文件取数据库链接参数
19 private void loadConnProperties(){
20 Properties props = new Properties();
21 try {
22 props.load(new FileInputStream(dbConnFile));//根据配置文件路径Conf加载配置文件
23 } catch (FileNotFoundException e) {
24 e.printStackTrace();
25 } catch (IOException e) {
26 e.printStackTrace();
27 }
28 this.dbDriver = props.getProperty("driver");//从配置文件中取得相应的参数并设置类变量
29 this.dbURL = props.getProperty("url");
30 this.userName = props.getProperty("username");
31 this.password = props.getProperty("password");
32
33 }
34
35 public boolean openConnection(){
36 try {
37 loadConnProperties();
38 Class.forName(dbDriver);
39 this.conn = DriverManager.getConnection(dbURL,userName,password);
40 return true;
41 } catch(ClassNotFoundException classnotfoundexception) {
42 classnotfoundexception.printStackTrace();
43 System.err.println("db: " + classnotfoundexception.getMessage());
44 } catch(SQLException sqlexception) {
45 System.err.println("db.getconn(): " + sqlexception.getMessage());
46 }
47 return false;
48 }
49
50
51 protected void finalize() throws Exception{
52 try {
53 if(null!=conn)
54 conn.close();
55 }catch (SQLException e) {
56 e.printStackTrace();
57 }
58
59 }
60
61 // 查询并得到结果集
62 public ResultSet execQuery(String sql) throws Exception {
63 ResultSet rstSet = null;
64 try {
65 if (null == conn)
66 throw new Exception("Database not connected!");
67 Statement stmt = conn.createStatement();
68 rstSet = stmt.executeQuery(sql);
69 } catch (SQLException e) {
70 e.printStackTrace();
71 }
72 return rstSet;
73 }
74
75 // 插入一条新纪录,并获取标识列的值
76 public ResultSet getInsertObjectIDs(String insertSql) throws Exception{
77 ResultSet rst = null;
78 try {
79 if(null==conn)
80 throw new Exception("Database not connected!");
81
82 Statement stmt = conn.createStatement();
83
84 stmt.executeUpdate(insertSql, Statement.RETURN_GENERATED_KEYS);
85 rst = stmt.getGeneratedKeys();
86
87 } catch (SQLException e) {
88 e.printStackTrace();
89 }
90 return rst;
91 }
92
93 //以参数SQL模式插入新纪录,并获取标识列的值
94 public ResultSet getInsertObjectIDs(String insertSql, Object[] params) throws Exception {
95 ResultSet rst = null;
96 PreparedStatement pstmt = null ;
97 try {
98 if (null == conn)
99 throw new Exception("Database not connected!");
100 pstmt = conn.prepareStatement(insertSql, Statement.RETURN_GENERATED_KEYS);
101
102 if(null != params){
103 for (int i = 0; i < params.length; i++) {
104 pstmt.setObject(i + 1, params[i]);
105 }
106 }
107 pstmt.executeUpdate();
108 rst = pstmt.getGeneratedKeys();
109 } catch (SQLException e) {
110 e.printStackTrace();
111 }
112 return rst;
113 }
114
115
116
117 // 插入、更新、删除
118 public int execCommand(String sql) throws Exception{
119 int flag = 0;
120 try {
121 if(null==conn)
122 throw new Exception("Database not connected!");
123
124 Statement stmt = conn.createStatement();
125 flag = stmt.executeUpdate(sql);
126
127 stmt.close();
128 } catch (SQLException e) {
129 e.printStackTrace();
130 }
131 return flag;
132 }
133
134 /* // 存储过程调用
135 public void callStordProc(String sql, Object[] inParams, SqlParameter[] outParams) throws Exception {
136 CallableStatement cst = null ;
137 try {
138 if (null == conn)
139 throw new Exception("Database not connected!");
140 cst = conn.prepareCall(sql);
141
142 if(null != inParams){
143 for (int i = 0; i < inParams.length; i++) {
144 cst.setObject(i + 1, inParams[i]);
145 }
146 }
147
148 if (null!=outParams){
149 for (int i = 0; i < inParams.length; i++) {
150 cst.registerOutParameter(outParams[i].getName(), outParams[i].getType());
151 }
152 }
153 cst.execute();
154 } catch (SQLException e) {
155 e.printStackTrace();
156 }
157 }
158 */
159 // 释放资源
160 public void close(ResultSet rst) throws Exception {
161 try {
162 Statement stmt = rst.getStatement();
163 rst.close();
164 stmt.close();
165 } catch (SQLException e) {
166 e.printStackTrace();
167 }
168 }
169
170 public PreparedStatement execPrepared(String psql) throws Exception {
171 PreparedStatement pstmt = null ;
172 try {
173 if (null == conn)
174 throw new Exception("Database not connected!");
175 pstmt = conn.prepareStatement(psql);
176 } catch (SQLException e) {
177 e.printStackTrace();
178 }
179 return pstmt;
180 }
181
182
183 // 释放资源
184 public void close(Statement stmt) throws Exception {
185 try {
186 stmt.close();
187 } catch (SQLException e) {
188 e.printStackTrace();
189 }
190 }
191
192 // 释放资源
193 public void close() throws SQLException, Exception{
194 if(null!=conn){
195 conn.close();
196 conn=null;
197 }
198 }
199
200 public Connection getConn() {
201 return conn;
202 }
203
204
205 public static void main(String[] args) {
206
207 }
208 }
3. DBUtil_TestDriver.java
测试程序。
1 import java.io.File;
2 import java.io.FileInputStream;
3 import java.io.FileOutputStream;
4 import java.io.InputStream;
5 import java.sql.ResultSet;
6
7 import java.sql.Blob;
8
9
10 public class DBUtil_TestDriver {
11
12 //测试一般数据写入
13 private static void test_insert(){
14 DBUtil db = new DBUtil();
15 db.openConnection();
16 String sql = "insert into studio(studio_name, studio_row_count, studio_col_count, studio_introduction )"
17 + " values(?,?, ?, ?)";
18 Object [] params = new Object[4];
19 params[0]=new String("test2");
20 params[1]=new Integer(2);
21 params[2]=new Integer(2);
22 params[3]=new String("just a test");
23 try {
24 ResultSet rst= db.getInsertObjectIDs(sql, params);
25
26 if (rst!=null && rst.first()) {
27 System.out.println(rst.getInt(1));
28 }
29
30 db.close(rst);
31 db.close();
32
33 } catch (Exception e) {
34 // TODO Auto-generated catch block
35 e.printStackTrace();
36 }
37
38 }
39
40 //测试lob数据写入
41 private static void test_insert_lob(){
42
43 String sql = "insert into play(play_type_id, play_lang_id, play_name, play_ticket_price, play_image )"
44 + " values(?,?, ?, ?, ?)";
45 Object [] params = new Object[5];
46 params[0]=null;
47 params[1]=null;
48 params[2]=new String("just a test");
49 params[3]=new Float(5);
50
51 FileInputStream fis = null;
52 File file = new File("resource/image/header.jpg"); //测试写图片
53
54 try {
55 DBUtil db = new DBUtil();
56 db.openConnection();
57 fis = new FileInputStream(file);
58 params[4]=fis;
59
60 ResultSet rst= db.getInsertObjectIDs(sql, params);
61
62 if (rst!=null && rst.first()) {
63 System.out.println(rst.getInt(1));
64 }
65
66 db.close(rst);
67 db.close();
68
69 } catch (Exception e) {
70 // TODO Auto-generated catch block
71 e.printStackTrace();
72 }
73
74 }
75
76 //测试lob数据读取
77 private static void test_read_lob(){
78 String sql = "select * from play";
79
80 FileInputStream fis = null;
81
82 try {
83 DBUtil db = new DBUtil();
84 db.openConnection();
85 ResultSet rst = db.execQuery(sql);
86 if (rst!=null) {
87 while(rst.next()){
88 System.out.println(rst.getString("play_name"));
89 System.out.println(rst.getFloat("play_ticket_price"));
90 int playID=rst.getInt("play_id");
91
92 byte[] buf = new byte[256];
93 Blob blob = rst.getBlob("play_image");
94 if(blob!=null ){
95 //需要在在工程目录下建立路径Cache/Play_Image/,然后将照片缓存到该路径下
96 File file = new File("Cache/Play_Image/"+ playID + ".jpg");
97 FileOutputStream sout = new FileOutputStream(file);
98 InputStream in = blob.getBinaryStream();//获取BLOB数据的输入数据流
99
100 for (int i = in.read(buf); i != -1;) {
101 sout.write(buf);
102 i = in.read(buf);
103 }
104 in.close();
105 sout.close();
106 }
107
108 }
109 }
110
111 db.close(rst);
112 db.close();
113
114 } catch (Exception e) {
115 // TODO Auto-generated catch block
116 e.printStackTrace();
117 }
118
119 }
120
121 public static void main(String[] args) {
122 // TODO Auto-generated method stub
123 //test_insert();
124 test_insert_lob();
125 test_read_lob();
126 }
127
128 }
至于数据库sql文件可自行设计,这里就不再编写了。