博主常用的数据库是Mysql,所以这篇文章就以MySQL为主。
数据库的访问过程
先来聊一聊数据库的访问过程,在Java后端开发中,访问数据库的过程如下:
- 客户端与Mysql服务器之间建立连接
- 客户端想MySQL服务器发送数据库请求
- MySQL服务器处理客户请求,并返回结果给客户
- 客户端接收MySQL服务器的响应,并按照自己的业务逻辑做响应处理
- 释放相关的资源。
JDBC的简介
在JDBC出现之前如图一,我们访问数据库的时候,需要专门正对数据库写一套访问程序,这不仅不利于程序的数据库迁移,而且也大大增加了程序员的工作量和影响到程序的性能。
图一、JDBC出现之前访问数据示例图
后来SUN公司为了简化数据库的开发,统一了对数据库的操作,定义了一套JDBC接口, JDBC的全称是:Java Data Base Connectivity(数据库连接),这套接口由数据库厂商去实现,这样开发人员学习JDBC接口的API,并通过JDBC加载具体的驱动,就可以操作数据库.
图二:JDBC 出现出现之后访问数据库示例图
开发JDBC应用需要两个包的支持,分别是Java.sql和Javax.sql,除了这两个包之外,还需要导入相应JDBC的数据库实现(即数据库驱动)笔者经常使用的是mysql-connector-java-5.1.47.jar.
常用url的写法
URL用于标识数据库的位置,程序员通过URL地址告诉JDBC程序连接哪个数据库,URL的写法为:
jdbc:mysql:[]//localhost:3306/test ?参数名=参数值
一些常用数据库url 写法
Oracle写法:jdbc:oracle:thin:@localhost:1521:dbname
SqlServer—jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=dbname
MySql—jdbc:mysql://localhost:3306/dbname
Mysql的url地址的简写形式: jdbc:mysql:///sid
如果你的主机地址默认是localhost 端口是3306
创建的JDBC的方式
创建JDBC之前需要现在MYSQL中创建一个数据库,并创建除相应的表,然后现将一个工程导入相应的驱动包,笔者在MySQL中创建了一个home数据库,创建了一张account表,后面都已此为例演示。
方式一
在已经创建好数据库、相应的表已经导入驱动包这些准备工作之后,下面需要进行的步骤是将驱动加载到驱动管理类中操作如下:
DriverManager.registerDriver(Driver driver)
之后需要建立相应的连接
Connection conn = DriverManager.getConnection(url,user,pass);
然后创建用于向数据库发送SQL的statement对象,并且发送SQL然后从代表结果集的Result中去除相应的数据,打印到命令窗口。
Statement startement = conn.createStatement();
ResultSet resultset = st.executeQuery(sql);//resultset 作为一个结果集,其底层是LIst,用于接收返回结果
最后断开数据库连接,释放相应的资源。
简单事例
首先 我们实现在MySQL中建立一个表account,并向其中插入数据 如下:
图三、MySQL中account表的表结构
图四、插入数据之后的account表
我们利用第一种创建JDBC的方式访问数据的代码实现如下:
package Test;
import java.sql.*;
import com.mysql.jdbc.Driver;
public class JDBCTest {
public static void main(String[] args) {
Connection connection=null;
Statement statement=null;
ResultSet resultSet=null;
try {
//将驱动加载到驱动管理类DriverManager中
DriverManager.registerDriver(new Driver());
//获取与数据库的连接
connection =DriverManager.getConnection("jdbc:mysql://localhost:3306/home?characterEncoding=utf8",
"root","12345");
//创建项数据库发送SQL语句的statement对象
statement = connection.createStatement();
//创建接收结果的结果集(这里以查为例)
resultSet= statement.executeQuery("select * from account");
while(resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
double salary = resultSet.getDouble("money");
System.out.println("id="+id+"\t"+"name="+name+"\t"+"salary="+salary);
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
connection.close();
statement.close();
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
程序运行结果如下:
图五、运行结果
虽然这一种方式可以创建JDBC 访问数据库,但是我们在使用中并不建议使用这种方式创建,因为当我们利用DriverManager.registerDriver(new Driver());
注册驱动时候,实际在Driver类的静态代码块已经将driver 注册了,下面让我们来看看Driver类的源码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.mysql.jdbc;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
我们可以看到当我们实例化Driver类的时候,静态代码块就会执行,并将该类注册,所以当我们在JDBC中执行DriverManager.registerDriver(new Driver()); 这个操作的时候实际上将驱动注册了两次,这是完全没有必要的,同时也会降低程序的性能。
方式二
在方式一中我们可以知道使用DriverManager.registerDriver(new Driver());这个操作的时候会将驱动注册两次,这是完全没有必要的,也会降低程序的性能,那么有没有更好的方式注册驱动呢?答案肯定是有的,在Driver类的源码中我们可以看到在其静态代码块中会实例一个Drive对象,并将其加载进DriverManager类中进行去驱动组成,根据这样的情况,我们可以通过反射机制直接得到Driver的class对象,而不用在外界实例化Driver类。
下面我们来写一个测试类
package Test;
import java.sql.*;
public class JDBCTest2 {
public static void main(String[] args) {
//获取与数据库的连接
Connection connection =null;
//创建项数据库发送SQL语句的statement对象
Statement statement=null;
//创建接收结果的结果集(这里以查为例)
ResultSet resultSet=null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/home?characterEncoding=utf8",
"root","123456");
statement = connection.createStatement();
resultSet =statement.executeQuery("select * from account");
while(resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
double salary = resultSet.getDouble("money");
System.out.println("id="+id+"\t"+"name="+name+"\t"+"salary="+salary);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally{
try { //关闭资源
connection.close();
statement.close();
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
程序结果:
可以看出和方式一都可以得到一样的结果,最大的区别就是将加载驱动类,直接利用反射机制直接生成class对象,这样就和好的避免了第二次注册驱动,我们在开发中最常用的也是第二种方式。
当然对于第二中方式我们可以两外写配置文件,将一些需要改变的量写在配置文件里,通过Properties类和IO流读取的方式加载程序,增加程序灵活性和适用性。