1. 程式人生 > >jdbc操作資料庫學習

jdbc操作資料庫學習

jdbc程式設計的步驟大致分為:

1.載入資料庫驅動,首先對於不同的資料庫要匯入其相應的jar包,我這裡是mysql資料庫,可直接在eclipse中建立maven專案,在maven中匯入其對應的jar包

以下為載入jdbc驅動

Class.forName("com.mysql.jdbc.Driver");

2.通過DriverManager獲取資料庫連線

其中第一個引數為mysql地址和其對應的埠(當然如果有伺服器也可以使用伺服器的公網ip和mysql的埠),第二個引數和第三個引數為mysql的使用者名稱和密碼

Connection conn = DriverManager.getConnection(
					"jdbc:mysql://127.0.0.1:3306/class",
					"root","123456"
				);

3.通過Statement物件執行sql語句,可通過Connection建立Statement物件

Statement stmt = conn.createStatement();

學過mysql的都知道sql語句分為

1、資料操縱語言(DML):用來操縱資料庫中資料的命令。包括:select、insert、update、delete。 2、資料定義語言(DDL):用來建立資料庫、資料庫物件和定義列的命令。包括:create、alter、drop。 3、資料控制語言(DCL):用來控制資料庫元件4.資料庫查詢語言(DQL):用來查詢資料庫
其中對於DML語言

執行DML時使用executeUpdate(sql)返回受影響的行數

執行DQL時使用executeQuery(sql)返回一個ResultSet物件,ResultSet中的next()方法使結果集的指標指向下一行,ResultSet結果集的指標預設指向第一行

ResultSet s = stmt.executeQuery("select languages.*"+"from languages"
					);
			while(s.next()) {
				System.out.println(s.getInt(1)+"\t"+s.getString(2));
			}
方法getInt(1)表示獲取第一列的資料,當然你如果知道列名也可以用列名做引數

執行DDL時使用 使用execute 返回型別為Boolean型別 表示執行該sql後是否返回ResultSet結果集 如果有 可以調getResultSet來返回ResultSet物件,getUpdateCount返回受影響的行數

使用PreparedStatement執行sql語句,在執行sql語句時,資料庫都會根據sql語句來建立新的執行計劃,如果反覆執行類似的sql語句,必定會降低資料庫的執行效率,所以使用預編譯的sql語句可大大提高資料庫效率,同時PreparedStatement還可有效的防止sql注入

PreparedStatement pstm = conn.prepareStatement("insert into jdbc_test values(null,?,1);");
		pstm.setString(1, "ruby");
		pstm.executeUpdate();

使用ResultSetMeteData分析結果集

//得到RsesultSetMetaData物件
		ResultSetMetaData rd = rs.getMetaData();
		//獲取列的數量
		int col_number = rd.getColumnCount();
		System.out.println("列的數量為"+col_number);
		//獲取指定索引的列名與列的型別
		for(int i = 1;i < col_number;i++) {
			System.out.println("索引"+i+"的列名:"+rd.getColumnName(i)+"型別:"+rd.getColumnTypeName(i));
		}

使用資料庫池管理連線:

資料庫每次建立連線都會消耗一定的時間,使用資料庫連線池的好處就是當用戶不使用連線是,把連線儲存起來,給下一個使用者使用,從而提高資料庫使用效率

BasicDataSource ds = new BasicDataSource();
		ds.setDriverClassName(driver);
		ds.setUrl(url);
		ds.setUsername(user);
		ds.setPassword(pass);
		ds.setInitialSize(2);
		ds.setMaxActive(100);
		//使用連線池中的資料庫連線
		Connection conn = ds.getConnection();
		String sql = "select * from languages";
		Statement st = conn.createStatement();
		ResultSet rs = st.executeQuery(sql);

封裝

為了使用jdbc的效率,不能每次都寫載入資料等一些重複的工作

所以我們可以寫一個工具類,提供一些方法來獲取和關閉連線

我這裡以資料庫連線池為例

import org.apache.commons.dbcp.BasicDataSource;

/**
 * 使用連線池技術管理資料庫連線
 * 
 * @author Administrator
 *
 */
public class DButil2 {
	// 資料庫連線池
	private static BasicDataSource ds;
	// 為不同執行緒管理連線
	private static ThreadLocal<Connection> tl;

	static {
		try {
			Properties prop = new Properties();

			// InputStream is =
			// DButil2.class.getClassLoader().getResourceAsStream("day01/config.properties");
			FileInputStream is = new FileInputStream("C:\\Users\\Administrator\\Desktop\\mysql.ini");
			prop.load(is);
			is.close();
			System.out.println("k");
			// 初始化連線池

			ds = new BasicDataSource();
			// 設定驅動 (Class.forName())
			ds.setDriverClassName(prop.getProperty("driver"));
			// 設定url
			ds.setUrl(prop.getProperty("url"));
			// 設定資料庫使用者名稱
			ds.setUsername(prop.getProperty("user"));
			// 設定資料庫密碼
			ds.setPassword(prop.getProperty("pwd"));
			// 初始連線數量
			ds.setInitialSize(Integer.parseInt(prop.getProperty("initsize")));
			// 連線池允許的最大連線數
			ds.setMaxActive(Integer.parseInt(prop.getProperty("maxactive")));
			// 設定最大等待時間
			// ds.setMaxWait(Integer.parseInt(prop.getProperty("maxwait")));
			// // 設定最小空閒數
			// ds.setMinIdle(Integer.parseInt(prop.getProperty("minidle")));
			// // 設定最大空閒數
			// ds.setMaxIdle(Integer.parseInt(prop.getProperty("maxidle")));
			// // 初始化執行緒本地
			tl = new ThreadLocal<Connection>();
			System.out.println("k");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 獲取資料庫連線
	 * 
	 * @throws SQLException
	 */
	// String sql = "select * from languages";

	public static Connection getConnection() {
		/*
		 * 通過連線池獲取一個空閒連線
		 */
		try {
			Connection conn = ds.getConnection();
			return conn;
		} 
		catch (Exception e) {
			//System.out.println("j");
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		// tl.set(conn);
	
	
	}

	/**
	 * 關閉資料庫連線
	 */
	public static void closeConnection(Connection conn) {
		try {

			if (conn != null) {
				/*
				 * 通過連線池獲取的Connection 的close()方法實際上並沒有將 連線關閉,而是將該連結歸還。
				 */
				conn.close();

			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

資料庫事物

我們知道資料庫的修改表上的資料時是自動提交 儲存  如果表上的資料被改動,沒有經過提交儲存就再次改就會丟擲異常 以下是一個例子

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;

import day01.DBUtil2;

/**
 * 與使用者相關的業務邏輯
 * 
 * @author Administrator
 *
 */
public class UserService {
	public static void main(String[] args) {
		/*
		 * 程式啟動後: 選擇1,2,3,4等操作 1:註冊新使用者 使用者ID從1開始 2:更改使用者資訊 3:刪除使用者資訊 4:查詢使用者資訊
		 */
		System.out.println("請輸入選項:");
		System.out.print("1:註冊  ");
		System.out.print("2:登入  ");
		System.out.print("3:修改  ");
		System.out.print("4:刪除  ");
		System.out.println("5:查詢  ");
		System.out.println("6:轉賬  ");
		Scanner scanner = new Scanner(System.in);
		int option = Integer.parseInt(scanner.nextLine().trim());

		switch (option) {
		case 1:
			// 註冊
			regUser(scanner);
			break;
		case 2:
			// 登入
			login(scanner);
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:
			break;
		case 6:
			giveMoney(scanner);
			break;
		}
	}

	/**
	 * 轉賬操作
	 * 
	 * @param scanner
	 */
	public static void giveMoney(Scanner scanner) {
		/*
		 * 1:獲取使用者輸入的資訊 2:必要的驗證,看看轉出賬戶餘額是否夠 --事務開始的地方 3:更新轉出賬戶的餘額 4:更新轉入賬戶的餘額 --提交事務的地方
		 */
		System.out.println("現在是轉賬操作");
		System.out.println("請輸入您的賬號");
		String fromUser = scanner.nextLine().trim();

		System.out.println("請輸入收款人的賬號");
		String toUser = scanner.nextLine().trim();

		System.out.println("請輸入轉出金額");
		String money = scanner.nextLine().trim();

		// 2
		String countSql = "SELECT money " + "FROM user_fanchuanqi " + "WHERE name='" + fromUser + "'";
		try {
			Connection conn = DBUtil2.getConnection();
			// 關閉自動提交事務
			conn.setAutoCommit(false);
			Statement state = conn.createStatement();
			ResultSet rs = state.executeQuery(countSql);
			// 判斷是否查詢出資料
			if (rs.next()) {
				int count = rs.getInt(1);
				// 判斷餘額是否足夠
				if (count >= Integer.parseInt(money)) {
					// 執行轉賬操作
					// 開始納入事務控制,因為開始執行DML操作了
					String fromSql = "UPDATE user_fanchuanqi " + "SET money=money-" + money + " " + "WHERE name='"
							+ fromUser + "'";
					// 修改當前使用者的餘額
					if (state.executeUpdate(fromSql) > 0) {

						// 修改收款人的餘額
						String toSql = "UPDATE user_fanchuanqi " + "SET money=money+" + money + " " + "WHERE name='"
								+ toUser + "'";
						if (state.executeUpdate(toSql) > 0) {
							System.out.println("轉賬成功");
							/*
							 * 兩次更新賬戶操作均成功,我們才 認為這次轉賬操作完畢。提交事務
							 */
							conn.commit();
						} else {
							System.out.println("轉賬失敗:沒有收款人" + toUser);
							/*
							 * 若第二次更新操作失敗,那麼整次 操作就算作失敗。應該回滾事務。
							 */
							conn.rollback();
						}
					}
				} else {
					System.out.println("餘額不足");
				}
			} else {
				System.out.println("沒有該使用者:" + fromUser);
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtil2.closeConnection();
		}
	}

	/**
	 * 登入操作
	 * 
	 * @param scanner
	 */
	public static void login(Scanner scanner) {
		/*
		 * 1:要求用輸入使用者名稱及密碼 2:根據使用者輸入作為條件去表中查詢 3:若查詢出資料,說明輸入正確
		 */
		System.out.println("現在是登入操作");
		System.out.println("請輸入使用者名稱:");
		String user = scanner.nextLine().trim();
		System.out.println("請輸入密碼:");
		String pwd = scanner.nextLine().trim();

		try {
			Connection conn = DBUtil2.getConnection();

			String sql = "SELECT * FROM user_fanchuanqi " + "WHERE name=? AND password=?";

			PreparedStatement ps = conn.prepareStatement(sql);

			ps.setString(1, user);
			ps.setString(2, pwd);

			ResultSet rs = ps.executeQuery();
			// 根據使用者輸入的能否查到資料
			if (rs.next()) {
				System.out.println("登入成功!");
			} else {
				System.out.println("使用者名稱或密碼錯誤!");
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtil2.closeConnection();
		}

	}

	/**
	 * 註冊操作
	 * 
	 * @param scanner
	 */
	public static void regUser(Scanner scanner) {
		/*
		 * 若是註冊操作: 1:獲取使用者輸入的相關資訊 2:獲取連線 3:獲取Statement 4:先獲取id的最大值 5:對該值+1,作為當前記錄的主鍵值
		 * 6:插入記錄 7:關閉連線
		 */
		try {
			// 1
			System.out.println("現在是註冊操作:");
			System.out.println("請輸入使用者名稱:");
			String user = scanner.nextLine().trim();
			System.out.println("請輸入密碼:");
			String pwd = scanner.nextLine().trim();
			System.out.println("請輸入賬戶金額:");
			String money = scanner.nextLine().trim();
			System.out.println("請輸入郵箱:");
			String email = scanner.nextLine().trim();

			// 2
			Connection conn = DBUtil2.getConnection();

			// 3
			Statement state = conn.createStatement();

			// 4
			String idSql = "SELECT MAX(id) id FROM user_fanchuanqi";

			// 5
			ResultSet rs = state.executeQuery(idSql);

			int id = -1;
			if (rs.next()) {
				id = rs.getInt("id");
			}
			// 統計出最大值後,對ID加1
			id++;
			rs.close();

			// 6
			/*
			 * INSERT INTO user_fanchuanqi VALUES(1,'jack','1234',5000,'[email protected]')
			 * 
			 */
			String sql = "INSERT INTO user_fanchuanqi " + "VALUES" + "(" + id + "," + "'" + user + "'," + "'" + pwd
					+ "'," + "" + money + "," + "'" + email + "'" + ")";
			System.out.println(sql);
			if (state.executeUpdate(sql) > 0) {
				System.out.println("註冊成功!歡迎你:" + user);
			} else {
				System.out.println("呵呵");
			}
			DBUtil2.closeConnection();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

批量更新資料

/**
 * 使用批處理批量更新資料
 * @author Administrator
 *
 */
public class BatchDemo {
	public static void main(String[] args){
		try{
			Connection conn
				= DBUtil2.getConnection();
			Statement state
				= conn.createStatement();
			
			for(int i=1000;i<20000;i++){
				String sql 
					="INSERT INTO user_fanchuanqi " +
					 "(id,name) " +
					 "VALUES" +
					 "("+i+",'test"+i+"')";
				
//				state.executeUpdate(sql);
				//快取,等待一起執行
				state.addBatch(sql);
				if(i%500==0){
					state.executeBatch();
					state.clearBatch();
				}		
			}
			state.executeBatch();
			
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			DBUtil2.closeConnection();
		}
	}