1. 程式人生 > 其它 >JDBC連線資料庫及對資料庫的操作

JDBC連線資料庫及對資料庫的操作

技術標籤:mysqljavajdbc

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的結果集做了處理,然後封裝。
增刪改操作相對簡單,返回值就是對資料庫中資料受影響的條數。
正在學習中,原創,謝謝!