手写MVC初体验(四)之手写JDBC框架(MySQL版本)
1. application.properties
spring.orm.database.driver=com.mysql.jdbc.Driver
spring.orm.database.url=jdbc:mysql://123.57.80.77:3344/forum_user?autoReconnect=true&useSSL=false&useUnicode=true&characterEncoding=utf-8&&allowMultiQueries=true
spring.orm.database.username=g15846456247
spring.orm.database.password=990408myj990408Myj-=_+
spring.orm.pool.size=4
spring.orm.pool.max=5
2. annotation——实体类注解
实体类的注解是要配合Example来使用的,下一篇会完善。
import java.lang.annotation.*;
/**
* @author gyh
* @csdn https://blog.csdn.net/qq_40788718
* @date 2020/7/10 22:48
*/
@Target({ElementType.TYPE})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String name() default "" ;
}
import java.lang.annotation.*;
/**
* @author gyh
* @csdn https://blog.csdn.net/qq_40788718
* @date 2020/7/10 22:48
*/
@Target({ElementType.TYPE})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String name() default "" ;
}
3. ConnectionPool——连接池
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author gyh
* @csdn https://blog.csdn.net/qq_40788718
* @date 2020/7/11 21:04
*/
public class ConnectionPool implements IConnectionPool{
//未使用的连接
private List<Connection> freeConnections ;
//已使用的连接
private List<Connection> usedConnections ;
//默认最大数量
private int maxSize = 5 ;
//默认最小数量
private int minSize = 1 ;
//初始化的数量
private int initSize ;
//当前数量
private AtomicInteger preSize = new AtomicInteger(0) ;
//等待时间
private long waitTimeOut = 1000 ;
//驱动类的路径
private String driver ;
//url
private String url ;
//username
private String username ;
//password
private String password ;
private final String driverProperty = "spring.orm.database.driver";
private final String urlProperty = "spring.orm.database.url";
private final String usernameProperty = "spring.orm.database.username";
private final String passwordProperty = "spring.orm.database.password";
private final String initSizeProperty = "spring.orm.pool.size" ;
private final String maxSizeProperty = "spring.orm.pool.max" ;
public ConnectionPool(Properties properties) throws Exception {
setDriver(properties.getProperty(driverProperty)) ;
setUrl(properties.getProperty(urlProperty)) ;
setUsername(properties.getProperty(usernameProperty)) ;
setPassword(properties.getProperty(passwordProperty)) ;
setMaxSize(properties.getProperty(maxSizeProperty));
setInitSize(properties.getProperty(initSizeProperty));
loaderJDBC() ;
setFreeConnections();
setUsedConnections();
createConnection(this.initSize) ;
}
private void loaderJDBC() {
try {
Class.forName(this.driver) ;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//创建连接
private synchronized void createConnection(int addSize) {
if (addSize + preSize.get() > maxSize){
return ;
}
Connection connection ;
for (int i=0 ; i<addSize ; i++){
try {
connection = DriverManager.getConnection(this.url , this.username , this.password) ;
this.freeConnections.add(connection) ;
preSize.incrementAndGet() ;
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//判断是否存活
private boolean isAlive(Connection connection){
try {
if (connection == null || connection.isClosed()){
return false ;
}
} catch (SQLException e) {
e.printStackTrace();
}
return true ;
}
//获取链接
public synchronized Connection getConnection(){
Connection connection = null ;
//空闲连接
if (freeConnections.size() > 0){
connection = this.freeConnections.remove(0) ;
this.preSize.decrementAndGet() ;
}else{
//没有空闲连接
int surplus = 0 ;
if ((surplus = this.maxSize - this.preSize.get()) > 0){
createConnection(surplus);
if (freeConnections.size() > 0){
connection = getConnection() ;
}
}else{
try {
wait(this.waitTimeOut);
} catch (InterruptedException e) {
e.printStackTrace();
}
connection = getConnection() ;
}
}
if (isAlive(connection)){
this.usedConnections.add(connection) ;
}
return connection ;
}
public synchronized void releaseConnection(Connection connection){
if (isAlive(connection)){
if (this.freeConnections.size() < this.maxSize){
this.freeConnections.add(connection) ;
}else{
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
this.usedConnections.remove(connection) ;
this.preSize.decrementAndGet() ;
notifyAll();
}
private boolean isNull(String param){
return param == null || "".equals(param) ;
}
private void setDriver(String driver) throws Exception {
if (isNull(driver)){
throw new Exception("database driver is null or empty") ;
}
this.driver = driver;
}
private void setUrl(String url) throws Exception {
if (isNull(url)){
throw new Exception("database url is null or empty") ;
}
this.url = url;
}
private void setUsername(String username) throws Exception {
if (isNull(username)){
throw new Exception("database username is null or empty") ;
}
this.username = username;
}
private void setPassword(String password) throws Exception {
if (isNull(password)){
throw new Exception("database password is null or empty") ;
}
this.password = password;
}
private void setFreeConnections() {
this.freeConnections = new Vector<Connection>(this.maxSize);
}
private void setUsedConnections() {
this.usedConnections = new Vector<Connection>(this.maxSize);
}
private void setMaxSize(String maxSize) {
this.maxSize = isNull(maxSize) ?
this.maxSize :
(Integer.parseInt(maxSize) > this.maxSize ?
this.maxSize : Integer.parseInt(maxSize)) ;
}
private void setInitSize(String initSize) {
this.initSize = isNull(initSize) ?
this.minSize :
(Integer.parseInt(initSize) > this.maxSize ?
this.minSize : Integer.parseInt(initSize)) ;
}
}
4. Executor——执行器
import org.framework.spring.v1.orm.annotation.Column;
import org.framework.spring.v1.orm.pool.ConnectionPool;
import org.framework.spring.v1.orm.sql.Example;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author gyh
* @csdn https://blog.csdn.net/qq_40788718
* @date 2020/7/11 21:02
*/
public class Executor {
public static ConnectionPool pool ;
public static <T> List<T> selectByExample(Example<T> example){
//下篇实现 类似于BaseMapper的类型
return null ;
}
//select
public static <T> List<T> selectSql(String sql , Class<T> object) throws SQLException, InstantiationException, IllegalAccessException {
Connection connection = pool.getConnection() ;
Statement st = connection.createStatement() ;
ResultSet rs = st.executeQuery(sql) ;
List<T> list = processRS(rs , object) ;
pool.releaseConnection(connection);
return list ;
}
private static <T> List<T> processRS(ResultSet rs, Class<T> object) throws SQLException, IllegalAccessException, InstantiationException {
Map<String,Field> colToField = getColToFieldMap(object) ;
String[] columnNames = getColumnNames(rs) ;
List<T> list = new ArrayList<T>() ;
String key ;
Field value ;
int size = columnNames.length ;
while(rs.next()){
T t = object.newInstance();
for (int i=0 ; i<size ; i++){
value = colToField.get(key = columnNames[i]) ;
if (value == null){
continue ;
}
if (value.getType() == Integer.class){
value.set(t , rs.getInt(key));
}else if (value.getType() == String.class){
value.set(t , rs.getString(key));
}else if (value.getType() == Long.class){
value.set(t , rs.getLong(key));
}else if (value.getType() == Float.class){
value.set(t , rs.getFloat(key));
}
}
list.add(t) ;
}
return list ;
}
private static String[] getColumnNames(ResultSet rs) throws SQLException {
ResultSetMetaData rsmd = rs.getMetaData() ;
int count = rsmd.getColumnCount() ;
String[] columnNames = new String[count] ;
for (int i=0 ; i<count ; i++){
columnNames[i] = rsmd.getColumnName(i+1) ;
}
return columnNames ;
}
private static Map<String, Field> getColToFieldMap(Class<?> object) {
Field[] fields = object.getDeclaredFields() ;
//列名 -> 属性对象
Map<String , Field> colToField = new HashMap<String , Field>() ;
for (int i=0 ; i<fields.length ; i++){
if (fields[i].isAnnotationPresent(Column.class)){
Column ic = fields[i].getAnnotation(Column.class) ;
fields[i].setAccessible(true);
colToField.put(ic.name() , fields[i]) ;
}
}
return colToField ;
}
//insert update delete
public static int execSql(String sql , Object... params) throws SQLException {
Connection connection = pool.getConnection() ;
PreparedStatement psql = connection.prepareStatement(sql);
for (int i = 1; i <= params.length; i++) {
if (params[i - 1] instanceof String) {
psql.setString(i, params[i - 1].toString());
} else if (params[i - 1] instanceof Double) {
psql.setDouble(i, Double.parseDouble(params[i - 1].toString()));
} else if (params[i - 1] instanceof Integer) {
psql.setInt(i, Integer.parseInt(params[i - 1].toString()));
} else {
psql.setString(i, params[i - 1].toString());
}
}
int sum = psql.executeUpdate();
psql.close();
pool.releaseConnection(connection);
return sum;
}
public static <T> int execByExample(Example<T> example){
return 0 ;
}
}