【JavaSE】數據庫連接的封裝 和 通用的基礎的增刪改查操作的封裝(支持LocalDatetime)

2020 - 4 - 25  :更新了BaseDao

根據項目需要,我完善了修正了BaseDao類,同時還可以支持將Java的LocalDatetime類型存到MySQL數據庫中(對應類型datetime)

BaseDao

import java.math.BigDecimal;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.Date;

/**
 * 基礎的數據庫操作類
 * 簡化通用的基礎的增刪改查的操作,與具體業務邏輯無關
 * @author passerbyYSQ
 */
public class BaseDao {
	
	public interface PackResult<T> {
		// 將ResultSet回調給子類,讓子類來處理ResultSet中的數據
        T onResultReturn(ResultSet rs) throws Exception; 
	}
	
	/**
	 * 通用的查詢操作
	 * @param <T>	查詢返回的數據,基類中無法確定,需要通過泛型拋給子類
	 * @param sql	sql語句(裏面有佔位符)
	 * @param pack	一個接口,該接口有個抽象方法將ResultSet回調給子類,讓子類來處理ResultSet中數據
	 * @param args	與佔位符一一對應的參數值
	 * @return		封裝後的查詢結果
	 */
	public static <T> T select(String sql, PackResult<T> pack, Object... args) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet resultSet = null;
		T result = null;
		try {
			conn = DruidHelper.getConnection();
			pstmt = conn.prepareStatement(sql);
			
			// 將參數設置到sql語句的佔位符中
			setValue(pstmt, args);
			//System.out.println(pstmt.toString());
			
			resultSet = pstmt.executeQuery();

			// 由於不同的表對應不同的實體類,在基類中無法實現將resultSet封裝成對應的實體類返回
			// 故只能通過接口中的回調函數交給子類去實現
			result = pack.onResultReturn(resultSet);
			return result;

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			DruidHelper.close(resultSet, pstmt, conn);
		}
	}
	
	/**
	 * 獲取結果集數量
	 * @param from	from部分,傳遞時不需要帶"from"。之所以傳遞from,而不是表名,是考慮到多表查詢
	 * @param where	where部分,傳遞時不需要帶"where",裏面含有佔位符
	 * @param args	代替佔位符的參數值
	 * @return		記錄數
	 */
	public static int getCount(String from, String where, Object... args) {
		String sql = "select count(*) from " + from + " where " + where;

		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet resultSet = null;
		try {
			conn = DruidHelper.getConnection();
			pstmt = conn.prepareStatement(sql);
			
			// 將參數設置到sql語句的佔位符中
			setValue(pstmt, args);
			
			resultSet = pstmt.executeQuery();
			return resultSet.next() ? resultSet.getInt(1) : -1;

		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		} finally {
			DruidHelper.close(resultSet, pstmt, conn);
		}

	}
	
	/**
	 *  插入記錄,比較適用於插入一條或幾條數據。不適合插入一個集合的數據
	 * @param sql	sql語句(裏面有佔位符)
	 * @param args	與佔位符一一對應的參數值
	 * @return		受影響的行數
	 */
	public static int insertOrUpdateOrDelete(String sql, Object... args) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		int count = 0;
		try {
			conn = DruidHelper.getConnection();
			pstmt = conn.prepareStatement(sql);
			
			// 將參數設置到sql語句的佔位符中
			setValue(pstmt, args);
			//System.out.println(pstmt.toString());
			
			// 受影響的行數
			count = pstmt.executeUpdate();
			return count;
			
		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		} finally {
			DruidHelper.close(pstmt, conn);
		}

	}

	/**
	 * 插入一條記錄。如果主鍵是自增長的,返回該條記錄的id
	 * 注意:主鍵必須是自增長的!!!
	 * @param sql
	 * @param args
	 * @return
	 */
	public static int insertReturnId(String sql, Object... args) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			conn = DruidHelper.getConnection();
			pstmt = conn.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);

			// 將參數設置到sql語句的佔位符中
			setValue(pstmt, args);
			//System.out.println(pstmt.toString());

			pstmt.executeUpdate();
			// 獲取最後插入的記錄的自增長id。修改是不會返回的
			rs = pstmt.getGeneratedKeys();

			return rs.next() ? rs.getInt(1) : 0;

		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		} finally {
			DruidHelper.close(rs, pstmt, conn);
		}
	}


	// 將參數設置到sql語句的佔位符中
	private static void setValue(PreparedStatement pstmt, Object... args) throws SQLException {
		for (int i = 0; i < args.length; i++) {	
			if (args[i] instanceof String) { // 主要
				pstmt.setString(i + 1, (String) args[i]);
			} else  if (args[i] instanceof Integer) { // 主要
				int num = (Integer) args[i];
				pstmt.setInt(i + 1, num);
			} else  if (args[i] instanceof LocalDateTime) { // 主要
				pstmt.setTimestamp(i + 1, Timestamp.valueOf((LocalDateTime) args[i]));
			} else if (args[i] instanceof Date) { // 主要 ((Date) args[i]).getTime()
				pstmt.setTimestamp(i + 1, new Timestamp(((Date) args[i]).getTime()));
			} else if (args[i] instanceof BigDecimal) {
				pstmt.setBigDecimal(i + 1, (BigDecimal) args[i]);
			} else if (args[i] instanceof Double) {
				pstmt.setDouble(i + 1, (Double) args[i]);
			} else if (args[i] instanceof Float) {
				pstmt.setFloat(i + 1, (Float) args[i]);
			} else if (args[i] instanceof Boolean) {
				pstmt.setBoolean(i + 1, (boolean) args[i]);
			} else {
				throw new RuntimeException("BaseDao類暫不支持set該數據類型");
			}
		}
	}
}

DbConnector

package dao;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * 數據庫連接類的封裝
 * 用於簡化獲取數據庫連接和關閉數據庫連接的操作
 * @author passerbyYSQ
 */
public class DbConnector {
	private static String driver;
	private static String url;
	private static String user;
	private static String password;
	
//	public static void main(String[] args) {
//		new DbConnector();
//	}
	
	/**
	 * 靜態代碼塊
	 * 配置信息的獲取和數據庫驅動的註冊,在第一次將JDBCUtil加載進內存時初始化一次即可
	 */
	static {
		try {
			ClassLoader classLoader = DbConnector.class.getClassLoader();
			// Eclipse中該配置文件位於src下
			URL resource = classLoader.getResource("JDBC.properties");
			// 使用URLDecoder.decode()解決路徑中的空格和中文字符問題
			String path = URLDecoder.decode(resource.getPath(), "utf-8"); 
			Properties properties = new Properties();
			
			// new BufferedInputStream(new FileInputStream(path))
			// new BufferedReader(new FileReader(new File(path)))
			properties.load(new BufferedInputStream(new FileInputStream(path)));
			
			driver = properties.getProperty("driver");
			url = properties.getProperty("url");
			user = properties.getProperty("user");
			password = properties.getProperty("password");
			
			// 註冊數據庫驅動
			Class.forName(driver); 
			System.out.println("註冊數據庫驅動");
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 獲取數據庫連接
	 * @return
	 * @throws SQLException
	 */
	public static Connection getConnection() throws SQLException {
		System.out.println("獲取數據庫連接");
		return DriverManager.getConnection(url, user, password);
	}
	
	/**
     * 釋放資源
     * @param stmt 	執行sql語句的對象
     * @param conn 	數據庫連接對象
     */
    public static void close(Statement stmt, Connection conn) {
        close(null, stmt, conn);
    }

    /**
     * 釋放資源的重載形式
     * @param rs 	結果集對象
     * @param stmt 	執行sql語句的對象
     * @param conn	 數據庫連接對象
     */
    public static void close(ResultSet rs, Statement stmt, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
	
}

BaseDao的使用

package test;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

import dao.BaseDao;

public class TestBaseDao {

	@Test
	public void testSelect() {
		String sql = "select * from user where sex = ?";
		System.out.println(sql);
		List<User> userList = BaseDao.select(sql, new BaseDao.PackResult<List<User>>() {
			@Override
			public List<User> onResultReturn(ResultSet rs) throws SQLException {
				List<User> users = new ArrayList<>();
				while (rs.next()) {					
					String name = rs.getString("name");
					String sex = rs.getString("sex");
					Long birthday = rs.getLong("birthday"); // 時間戳
					// 由於密碼是隱私數據,所以我們不將密碼返回給前端頁面
					users.add(new User(name, null, sex, birthday));					
				}				
				return users;
			}
			
		}, "男");
		
		for(User user : userList) {
			System.out.println(user);
		}
	}
	
//	@Test
//	public void testInsert() {
//		String sql = "insert into user values(NULL, ?, ?, ?, NULL)";
//		int count = BaseDao.insertOrUpdateOrDelete(sql, "efg", "123", "女");
//		System.out.println(count);
//	}
	
	
	class User {
		private String name;
		private String password;
		private String sex;
		private Long birthday;
		
		public User(String name, String password, String sex, Long birthday) {
			this.name = name;
			this.password = password;
			this.sex = sex;
			this.birthday = birthday;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public String getPassword() {
			return password;
		}

		public void setPassword(String password) {
			this.password = password;
		}

		public String getSex() {
			return sex;
		}

		public void setSex(String sex) {
			this.sex = sex;
		}

		public Long getBirthday() {
			return birthday;
		}

		public void setBirthday(Long birthday) {
			this.birthday = birthday;
		}

		@Override
		public String toString() {
			return "User [name=" + name + ", password=" + password + ", sex=" + sex + ", birthday=" + birthday + "]";
		}
		
	}
}

配置文件:JDBC.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost/數據庫名稱?characterEncoding=UTF-8
user=用戶名
password=密碼

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章