JDBC連線資料庫及對資料庫的操作
JDBC連線資料庫及對資料庫的操作
JDBC分為兩部分,一是對獲取連線,二是對資料庫的sql操作。
一.JDBC連線資料庫
JDBC連線資料庫,主要分為兩個,1.直接獲取 2.使用DataSource(資料庫連線池)
1.1入門階段直接獲取連線
直接通過類載入器載入配置檔案,然後通過DriverManager來獲取Connection物件。
在這裡做成了一個工具類,主要有載入配置檔案,註冊驅動,獲取Connection物件,以及關流等操作。
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
private static String driverClass=null;
private static String url=null;
private static String user=null;
private static String password=null;
//載入資料庫配置檔案
static {
InputStream is=null;
Properties ps=new Properties();
try {
is=JDBCUtils.class .getClassLoader().getResourceAsStream("JDBC.properties");
ps.load(is);
driverClass=ps.getProperty("driverClass");
url=ps.getProperty("url");
user=ps.getProperty("user");
password=ps.getProperty("password");
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//獲取資料庫連線
public static Connection getConn(){
Connection conn=null;
try {
//載入資料庫驅動
Class.forName(driverClass);
//獲取資料庫連線
conn= DriverManager.getConnection(url,user,password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return conn;
}
//釋放資源
public static void close(Connection conn, Statement stmt, ResultSet rs){
try {
rs.close();
stmt.close();
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
//方法的過載,再定義一個關閉資源的方法,兩個引數
public static void close(Connection conn, Statement stmt){
try {
stmt.close();
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
1.2 提升階段使用資料庫連線池
資料庫連線池就是一開始就在記憶體中開闢一塊空間(集合) , 一開先往池子裡面放置 多個連線物件。 後面需要連線的話,直接從池子裡面去。不要去自己建立連線了。 使用完畢, 要記得歸還連線。確保連線物件能迴圈利用。
DataSource是sun公司針對java中的資料庫連線池定義的一套規範,所有提供資料庫連線池的第三方,必須實現此介面。
需要注意的是關流與上面不同,上面的關流是斷開連線,然後Connection物件就被gc回收了,而資料庫連線池是將其歸還給連線池,然後還能再次使用。
1.2.1 DBCP開源資料庫連線池
首先使用要匯入jar包,其實現是通過關鍵類 BasicDataSource來獲取DataSource,通過DataSource物件來獲取Connection,進行資料庫連線。
在這裡也做了一個工具類
import org.apache.commons.dbcp.BasicDataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
public class Utils {
private static String driverclass=null;
private static String url=null;
private static String username=null;
private static String password=null;
private static BasicDataSource dataSource;
//載入配置檔案,配置資料庫連線池
static {
InputStream is=Utils.class.getClassLoader().getResourceAsStream("DBCP.properties");
Properties ps=new Properties();
try {
ps.load(is);
} catch (IOException e) {
e.printStackTrace();
}
driverclass=ps.getProperty("driverClassName");
url=ps.getProperty("url");
username=ps.getProperty("username");
password=ps.getProperty("password");
dataSource=new BasicDataSource();
dataSource.setDriverClassName(driverclass);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
}
//獲取資料庫連線物件
public static Connection getConn(){
Connection conn=null;
try {
conn=dataSource.getConnection();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return conn;
}
public static void close(Connection conn, PreparedStatement ps, ResultSet rs){
try {
//關流加個判空操作
if (rs!=null){
rs.close();
}
if (ps!=null){
ps.close();
}
if (conn!=null){
conn.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
public static void close(Connection conn,PreparedStatement ps){
try {
if (ps!=null){
ps.close();
}
if (conn!=null){
conn.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
public static void close(Connection conn){
try {
if (conn!=null){
conn.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
1.2.2 C3P0資料庫連線池
C3P0資料庫連線池應用較廣泛,主要是通過ComboPooledDataSource來獲取DataSource,然後再獲取Connection物件。
dbcp沒有自動回收空閒連線的功能
c3p0有自動回收空閒連線功能
兩者主要是對資料連線的處理不同c3p0提供最大空閒時間,dbcp提供最大連線數。前者是如果連線時間超過最大連線時間,就會斷開當前連線。dbcp如果超過最大連線數,就會斷開所有連線。
DBCP有著比C3P0更高的效率,但是實際應用中,DBCP可能出現丟失連線的可能,而C3P0穩定性較高。因此在實際應用中,C3P0使用較為廣泛。
使用C3P0資料庫連線池首先匯入jar包,然後配置c3p0-config.xml配置檔案。主要如下所示:
<c3p0-config>
<!-- 使用預設的配置讀取連線池物件 -->
<default-config>
<!-- 連線引數 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/Java01</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 連線池引數 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">10</property>
<property name="checkoutTimeout">3000</property>
</default-config>
<!-- 這個name可以在建立DataSource時當做引數傳進去,使用這個配置-->
<named-config name="otherc3p0">
<!-- 連線引數 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/Java01</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 連線池引數 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>
配置檔案一切就緒(配置檔案必須放在src目錄下,自動去bin目錄下的class檔案中讀,然後解析),開始建立連線,程式碼如下所示:
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class Demo01 {
public static void main(String[] args) {
ComboPooledDataSource dataSource=new ComboPooledDataSource();
try {
Connection conn=dataSource.getConnection();
//列印測試,已獲取連線
System.out.println(conn);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
1.2.3 阿里的Druid資料庫連線池
阿里的Druid資料庫連線池是目前最好的,使用DruidDataSourceFactory工廠建立DataSource物件,引數需要Properties。返回一個DataSource物件,然後再獲取Connection物件。
具體如下:
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
//阿里的druid資料庫連線池
public class Test01 {
public static void main(String[] args) {
Properties properties=new Properties();
//獲取配置檔案的輸入流
InputStream is=Test01.class.getClassLoader().getResourceAsStream("druid.properties");
DataSource dataSource=null;
Connection connection=null;
try {
//載入配置檔案
properties.load(is);
//使用DruidDataSourceFactory工廠建立DataSource物件,引數需要Properties。返回一個DataSource物件
dataSource= DruidDataSourceFactory.createDataSource(properties);
//獲取連線物件
connection=dataSource.getConnection();
//列印輸出測試,輸出地址值,說明獲取成功
System.out.println(connection);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
二.對資料庫sql語句的操作–增刪改,查
2.1 使用Statement物件,操作sql語句
直接使用Statement物件,操作查詢的sql語句,如下所示:
public static void find() {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConn();
stmt = conn.createStatement();
String sql = "select * from student";
//返回一個ResultSet的結果集
rs = stmt.executeQuery(sql);
// 遍歷資料集
while (rs.next()) {
int id = rs.getInt("id");
String sid=rs.getString("sid");
String name = rs.getString("name");
int age = rs.getInt("age");
String gender = rs.getString("gender");
System.out.println("id:" + id +";sid:"+sid +";name:" + name + ";age:" + age + ";gender:" + gender);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
JDBCUtils.close(conn, stmt, rs);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
刪除操作:
//刪除學生資訊
public static void delete() {
Scanner sc = new Scanner(System.in);
Connection conn = null;
Statement stmt = null;
int result = 0;
try {
conn = JDBCUtils.getConn();
stmt=conn.createStatement();
System.out.println("請輸入要刪除的學生sid:");
String sid=sc.next();
String sql="delete from student where sid='"+sid+"'";
//返回對資料庫語句的改動條數
result=stmt.executeUpdate(sql);
sc.nextLine();
if (result>0) {
System.out.println("您已成功刪除該學生資訊");
}else {
System.out.println("刪除失敗!");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
JDBCUtils.close(conn, stmt);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
查詢比較複雜,有個結果集需要處理,而增刪改相對簡單。增刪改都類似。
使用Statement物件,操作sql語句容易產生SQL注入。因此可用PreparedStatement物件,使用佔位符,可預編譯sql語句。
2.2 使用PreparedStatement物件,操作sql語句
使用PreparedStatement物件來操作sql語句,可防止sql注入
具體程式碼如下:
查詢功能:
//獲取到全部的學生,放到集合中,返回該集合
@Override
public List<Student> findAll() {
ArrayList<Student> list=new ArrayList<>();
try {
//獲取資料庫連線物件
conn=JDBCUtils.getConn();
//定義sql語句
String sql="select * from student";
//獲取PreparedStatement(sql語句傳輸)物件,預編譯sql語句
ps=conn.prepareStatement(sql);
//執行sql語句
rs=ps.executeQuery();
Student student=null;
while (rs.next()) {
//將其屬性值取出來
int id=rs.getInt("id");
String sid=rs.getString("sid");
String name=rs.getString("name");
int age=rs.getInt("age");
String gender=rs.getString("gender");
//建立一個學生物件
Student stu=new Student(id,sid,name,age,gender);
//放到集合中
list.add(stu);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JDBCUtils.close(conn,ps,rs);
}
return list;
}
刪除方法:
@Override
public void delete() {
//獲取到全部的學生
List<Student> list=findAll();
System.out.println("請輸入要刪除的學生sid:");
String sid=sc.next();
boolean flag=false;
for (int i = 0; i < list.size(); i++) {
if (sid.equals(list.get(i).getSid())){
flag=true;
break;
}
}
if(flag){
//若為true則說明資料庫中存在這個資料,可以進行刪除
try {
conn=JDBCUtils.getConn();
String sql="delete from student where sid=?";
ps=conn.prepareStatement(sql);
//填充佔位符
ps.setString(1,sid);
int result=ps.executeUpdate();
if (result>0){
System.out.println("刪除成功!");
}else {
System.out.println("刪除失敗!");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JDBCUtils.close(conn,ps);
}
}else {
System.out.println("查無此人!請核實正確的sid");
}
}
增刪改方法類似
2.3 使用DBUtils操作sql語句
DBUtils是Apache給我們提供的簡化了JDBC對資料庫進行操作的過程。
注意:dbutils 只是幫我們簡化了CRUD(增刪改查) 的程式碼, 但是連線的建立以及獲取工作。 不在他的考慮範圍
dbutils的兩個關鍵類, QueryRunner(調update,query方法) and ResultSetHandler(查詢 返回的結果集)
在這裡藉助c3p0連線池來獲取連線物件。
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import java.sql.Connection;
import java.sql.SQLException;
public class DBUtilsTest01 {
public static void main(String[] args) {
ComboPooledDataSource dataSource=new ComboPooledDataSource();
QueryRunner qr=new QueryRunner();
Connection conn=null;
try {
conn=dataSource.getConnection();
String sql="insert into test values(null,?,?)";
//可變參的底層是一個數組,因此可以直接定義一個object型別的陣列,將插入的值放入,調update方法,傳入陣列
/*Object[] obj={"小明",29};
int result= qr.update(conn,sql,obj);*/
//第三個引數填充sql語句的佔位符
int result= qr.update(conn,sql,"clearlove",25);
if (result>0){
System.out.println("新增成功!");
}else {
System.out.println("新增失敗!");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
增刪改操作類似。
查詢操作 第一種:
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public class DBUtilsTest02 {
public static void main(String[] args) {
ComboPooledDataSource dataSource=new ComboPooledDataSource("c3p0-config.xml");
QueryRunner qr=new QueryRunner();
Connection conn=null;
try {
conn=dataSource.getConnection();
String sql="select * from test";
//需要一個ResultSetHandler型別的物件,建立它的子類
ArrayListHandler alh=new ArrayListHandler();
//結果接收
List<Object[]> array=qr.query(conn,sql,alh);
//遍歷查詢結果
for (Object[] obj : array) {
for (Object objects : obj) {
System.out.println(objects);
}
}
//這種方式只取第一條資料
/* ArrayHandler ah=new ArrayHandler();
Object[] obj=qr.query(conn,sql,ah);
for (Object o : obj) {
System.out.println(o);
}*/
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
查詢操作 第二種:
使用BeanListHandler,藉助反射,將資料載入到JavaBean類中,將物件放入list集合
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public class DBUtilsTest03 {
public static void main(String[] args) {
ComboPooledDataSource dataSource=new ComboPooledDataSource("c3p0-config.xml");
QueryRunner qr=new QueryRunner();
Connection conn=null;
try {
conn=dataSource.getConnection();
String sql="select * from user";
//使用BeanListHandler,返回一個list集合
List<User> list= qr.query(conn,sql,new BeanListHandler<User>(User.class));
for (User user : list) {
System.out.println(user);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
2.4 使用Spring框架的JDBCTemplate來操作sql語句
在這裡使用c3p0作為連線池來獲取資料庫連線,使用 JdbcTemplate類來獲取例項,調update,query方法
插入方法:
@Test
public void add(){
ComboPooledDataSource dataSource=new ComboPooledDataSource();
JdbcTemplate jt=new JdbcTemplate(dataSource);
String sql="insert into user values('陌離','888888')";
int result=jt.update(sql);
if (result>0){
System.out.println("插入成功!");
}else {
System.out.println("插入失敗!");
}
}
增刪改操作類似,也可用佔位符來定義sql的value。
查詢方法 第一種:
queryForList(sql)方法 返回值型別為list集合巢狀map<String,Object>集合
//查詢全部,返回值型別為list集合巢狀map<String,Object>集合
@Test
public void find1(){
ComboPooledDataSource dataSource=new ComboPooledDataSource();
JdbcTemplate jt=new JdbcTemplate(dataSource);
String sql="select * from user";
//返回值型別為list集合巢狀map集合
List<Map<String,Object>>list=jt.queryForList(sql);
for (Map<String, Object> map : list) {
Set<String> set=map.keySet();
Iterator<String> it=set.iterator();
while (it.hasNext()){
String next = it.next();
System.out.println(next+":"+map.get(next));
}
}
}
查詢方法 第二種:
query(sql,rowMapper) 將結果集封裝為JavaBean物件,放到list集合中。返回list型別的集合
//查詢所有,利用反射將將查詢到的結果載入到Bean類中,將User物件放入list集合中
//將結果集封裝為JavaBean物件,放到list集合中。
@Test
public void find2(){
ComboPooledDataSource dataSource=new ComboPooledDataSource();
JdbcTemplate jt=new JdbcTemplate(dataSource);
String sql="select * from user";
RowMapper<User> rowMapper=new BeanPropertyRowMapper<>(User.class);
List<User> list=jt.query(sql,rowMapper);
for (User user : list) {
System.out.println(user);
}
}
查詢方法 第三種 查詢一條:
queryForMap(),只查詢一條資料,適合單個查詢
//只查詢一條資訊 queryForMap()
@Test
public void find3(){
ComboPooledDataSource dataSource=new ComboPooledDataSource();
JdbcTemplate jt=new JdbcTemplate(dataSource);
String sql="select * from user where Username=?";
Map<String,Object> map=jt.queryForMap(sql,"陌離");
System.out.println(map);
}
其實不管是DBUTils還是JdbcTemplate,其原理類似,關於查詢這一塊,底層都是對ResultSet的結果集做了處理,然後封裝。
增刪改操作相對簡單,返回值就是對資料庫中資料受影響的條數。
正在學習中,原創,謝謝!