1. 程式人生 > >JDBC操作資料庫基礎

JDBC操作資料庫基礎

JDBC操作資料庫

一、JDBC的概念

JDBC:JavaDataBaseConnection:通過java程式碼操作資料庫。可以把JDBC看成一個操作Mysql的一個客戶端。 JDBC使用步驟: 1、載入mysql的驅動類:mysql-connector-java-5.1.7-bin.jar。 2、建立資料庫與JAVA之間的連線:DriverManager.getConnection(url, user, password);url是資料庫連線地址:jdbc:mysql://localhost:3306/資料庫名。此處連得是本機。user是使用者名稱,password是資料庫登入密碼。 3、通過Connection物件建立Statement物件,conn.createStatement(); 4、通過Statement傳送SQL語句,executeUpdate():只能傳送DML語句,executeQuery();可以執行DQL語句。

程式碼如下:

public class JDBCDemo1 {
	//資料庫連線地址:
	//jdbc:mysql://mysql's ip:3306/資料庫名
	private static String url 
			= "jdbc:mysql://127.0.0.1:3306/ph";
	private static String user = "j180703";
	private static String password = "123456";
	//驅動類名
	private static String driverClassName 
			= "com.mysql.jdbc.Driver";
	/**
	 * 建立資料庫連線,並返回該連線物件
	 * @return 連線物件
	 */
	public static Connection getConnection(){
		//DriverManager負責安裝資料庫驅動
		Connection conn = null;
		try {
			//載入com.mysql.jdbc.Driver類到JVM
			Class.forName(driverClassName);
			//通過DriverManager建立資料庫連線
			conn = DriverManager.getConnection(
					url, user, password);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return conn;
	}
	
	/**
	 * 向學生表插入一行記錄,使用DML語句
	 * @param args
	 */
	public static void insertDemo(){
		try {
			//1.獲取連線
			Connection conn = getConnection();
			//2.通過Connection物件建立Statement物件
			Statement stmt = conn.createStatement();
			//3.編寫sql語句
			String sql = "insert into t_student " + 
				"values(null,'phooxx2b','男',28," + 
				"'2018-08-01','
[email protected]
',1)"; //4.通過Statement傳送SQL //executeUpdate():只能傳送DML語句 int result = stmt.executeUpdate(sql); if(result!=1){ System.out.println("插入失敗!"); }else{ System.out.println("插入成功!"); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 查詢學生表中的所有記錄,使用的是DQL語句 */ public static void queryDemo(){ try { //1.獲取連線 Connection conn = getConnection(); //2.通過Connection物件建立Statement物件 Statement stmt = conn.createStatement(); //3.編寫sql String sql = "select * from t_student"; //4.傳送Sql //傳送DQL使用executeQuery(),返回值為ResultSet //ResultSet結果集,該物件封裝了查詢結果 //ResultSet有行有列,它就是虛擬表 ResultSet rs = stmt.executeQuery(sql); //取出ResultSet中的結果: //一次取一行,迴圈去取,直到取完 //rs.next():判斷是否有下一行,如果有直接取出 //相當於迭代器的hasNext()+next() while(rs.next()){ //next()一次就取出了一行 //取一行中的各列值: System.out.println(rs.getInt("student_id")); System.out.println(rs.getString("student_name")); System.out.println(rs.getString("sex")); System.out.println("-----------"); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } }

Statement的缺點: 1、拼寫sql容易出錯 2、不能防止sql注入 因此開發中我們常用PreparedStatement來執行sql語句。(sql注入不懂的可以上網查查,在這裡就不在細講。)

使用PreparedStatement來進行資料庫操作
public class DBUtil {
		private static String url;
		private static String user;
		private static String password;
		//驅動類名
		private static String driverClassName ;
		//static程式碼塊會在類被JVM載入是立即執行
		//讀取db.properties檔案,並給靜態屬性賦值
		static{
			//1、讀取db.properties檔案
			//讀取src以及同級目錄下的檔案
			//1.1getClassLoader()獲取config的classloader
			//獲取IO流
			InputStream in = DBUtil.class.getClassLoader().
							getResourceAsStream("db.properties");
			//1.2建立properties物件
			//專門讀取.properties檔案工具類
			Properties prop = new Properties();
			try {
				//載入輸入流
				prop.load(in);
			} catch (IOException e) {
				e.printStackTrace();
			}
			//2、給靜態屬性賦值
			url = prop.getProperty("jdbc.url");
			user = prop.getProperty("jdbc.user");
			password = prop.getProperty("jdbc.password");
			driverClassName = prop.getProperty("jdbc.driverClassName");
		}
		
		/**
		 * 建立資料庫連線,並返回該連線物件
		 * @return 連線物件
		 */
		public static Connection getConnection(){
			//DriverManager負責安裝資料庫驅動
			Connection conn = null;
			try {
				//載入com.mysql.jdbc.Driver類到JVM
				Class.forName(driverClassName);
				//通過DriverManager建立資料庫連線
				conn = DriverManager.getConnection(
						url, user, password);
			} catch (Exception e) {
				e.printStackTrace();
			}
			return conn;
		}
		
		/**
		 * general:通用
		 * 封裝一個通用增刪改方法
		 * @param sql Object... params:佔位符:
		 *Object... 表示引數個數不確定,但必須放在最後一個引數位置
		 *相當於一個數組
		 */
		public static int generalUpadate(String sql,Object... params){
			int result = 0;
			Connection conn = null;
			PreparedStatement pstmt = null;
			try {
				conn = getConnection();
				//此處執行sql語句,但佔位符處值為空
				pstmt = conn.prepareStatement(sql);
				//給sql中的佔位符賦值
				if(params!=null){
					for (int i = 0; i < params.length; i++) {
						pstmt.setObject(i+1, params[i]);
					}
				}
				//將賦值過的佔位符值傳給sql語句
				result = pstmt.executeUpdate();
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				closeAll(conn,pstmt,null);
			}
			return result;
		}
		
		/**
		 * 通用查詢,可以查詢任意表,可以把查詢結果封裝成任意物件
		 * Java類的屬性名要和資料庫的列名一致
		 * 因為是通過列名反射得到的屬性名
		 * @param <X> 佔位符,宣告泛型
		 * @param cls 要封裝物件的類物件
		 * @param sql 查詢語句
		 * @param params sql語句中的佔位符值:Object... 
		 */
		public static <X> List<X>  generalQuery(Class<X> cls,String sql,Object...params){
			List<X> list = new ArrayList<>();
			Connection conn = null;
			PreparedStatement pstmt = null;
			ResultSet rs = null;
			try {
				conn = getConnection();
				pstmt = conn.prepareStatement(sql);
				//給sql中佔位符賦值
				if(params!=null){
					for (int i = 0; i < params.length; i++) {
						pstmt.setObject(i+1, params[i]);
					}
				}
				//將佔位符的值傳過去
				rs = pstmt.executeQuery();
				//如何獲取列名
				//ResultSetMetaData:封裝了列的名和列的總數
				ResultSetMetaData md = rs.getMetaData();
				//獲取列的總數
				int columnCount = md.getColumnCount();
				//md.getColumnName(column):通過列號獲取列名
				X x = null;
				String columnName = null;
				while(rs.next()){
					//一行記錄對應一個物件
					x = cls.newInstance();
					//給物件屬性賦值
					//獲取列名,為反射做準備
					//一行有很多列,列號從一開始
					for (int i = 1; i <= columnCount; i++) {
						columnName = md.getColumnName(i);
						//取出一個列名,反射得到一個屬性
						try {
							//1、獲取父類類物件
							Class<?> superCls = cls.getSuperclass();
							if(superCls == Object.class){
								//如果一個類無直接父類,那麼該類屬性全在本類中
								throw new NoSuchFieldException();
							}
							Field superField = superCls.getDeclaredField(columnName);
							//無異常表示屬性屬於父類,給屬性賦值
							superField.setAccessible(true);
							superField.set(x, rs.getObject(i));
							
						} catch (NoSuchFieldException e) {
							// TODO: handle exception
						//	e.printStackTrace();
							//丟擲異常屬性在子類中
							Field childField = cls.getDeclaredField(columnName);
							childField.setAccessible(true);
							childField.set(x, rs.getObject(columnName));
						}
					}
					//迴圈一次結束講物件加到集合中
					list.add(x);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				closeAll(conn, pstmt, rs);
			}
			return list;
		}
		
		/**
		 * 關閉資源
		 * Connection,Statement,ResultSet
		 */
		public static void closeAll(Connection conn,Statement stmt,ResultSet rs){
			try {
				//先開的後關
				if(rs!=null){
					rs.close();
				}
				if(stmt!=null){
					stmt.close();
				}
				if(conn!=null){
					conn.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
			System.out.println(getConnection());
		}
}