类图
此类图主要是获取数据库类图,DataBaseOperation是一个接口,定义了数据库的主要操作;AbstractDataBaseOperationFactory是一个抽象类,是所有数据库操作的基类,所有的数据库局要继承次此类,去实现特定的操作;此类图中使用了模板方法。
其相关的代码如下
DataBaseOperation.java
package com.framework.betterorm.Datesource;
import java.sql.Connection;
/**
*
* 数据库通用操作
*/
public interface DataBaseOperation {
/**
* 数据库连接方法
*/
Connection connect();
/**
* 执行SQL语句(除select)
*/
int update(String sql, Object object);
/**
* 执行select语句
*/
Object select(String sql, Object o);
}
AbstractDataBaseOperationFactory.java
package com.framework.betterorm.Datesource;
import com.framework.betterorm.reflection.ObjectFields;
import com.framework.betterorm.utils.YamlHelper;
import com.framework.betterorm.parsing.PropertyParser;
import java.sql.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
public abstract class AbstractDataBaseOperationFactory implements DataBaseOperation {
public static String databaseType;
/**
* 声明一个 Connection类型的静态属性,用来缓存一个已经存在的连接对象
*/
public static Connection conn = null;
/**
* 用户名
*/
protected static String username;
/**
* 密码
*/
protected static String password;
/**
* 是否自动提交事务
*/
protected static boolean autoCommit = false;
protected static String url;
static {
config(Objects.requireNonNull(AbstractDataBaseOperationFactory.class.getClassLoader().getResource("DataBaseConfig.yml")).getFile());
}
/**
* 获取文件的连接信息,采用最简洁的yaml文件
*/
private static void config(String file) {
System.out.println("config");
if (YamlHelper.fileRead(file) == null) {
return;
}
Map<String, Object> infoMap = (Map<String, Object>) YamlHelper.fileRead(file).get("Datasource");
if (infoMap.size() <= 0) {
return;
}
//获取用户名
username = String.valueOf(infoMap.get("username")).trim();
//获取密码
password = String.valueOf(infoMap.get("password")).trim();
//设置是否自动提交
autoCommit = false;
if (infoMap.get("autoCommit") != null) {
autoCommit = (boolean) infoMap.get("autoCommit");
}
//获取连接字符串
url = String.valueOf(infoMap.get("url")).trim();
databaseType = url.split(":")[1];
}
/**
* 释放资源
**/
public static void release(Object cloaseable) {
if (cloaseable != null) {
if (cloaseable instanceof ResultSet) {
ResultSet rs = (ResultSet) cloaseable;
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (cloaseable instanceof Statement) {
Statement st = (Statement) cloaseable;
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (cloaseable instanceof Connection) {
Connection c = (Connection) cloaseable;
try {
c.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* 回滚事务
*/
private static void rollback(Connection c) {
if (c != null && !autoCommit) {
try {
c.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private static Object typeof(Object o) {
Object r = o;
if (o instanceof Timestamp) {
return r;
}
// 将 java.util.Date 转成 java.session.Date
if (o instanceof java.util.Date) {
java.util.Date d = (java.util.Date) o;
r = new Date(d.getTime());
return r;
}
// 将 Character 或 char 变成 String
if (o instanceof Character || o.getClass() == char.class) {
r = String.valueOf(o);
return r;
}
return r;
}
public String getInstance() {
return this.getClass().getSimpleName();
}
/**
* 有子类实现
*/
@Override
public abstract Connection connect();
/**
* 专门检查缓存的连接是否不可以被使用 ,不可以被使用的话,就返回 true
*/
protected boolean invalid() {
if (conn != null) {
try {
//isValid方法是判断Connection是否有效,如果连接尚未关闭并且仍然有效,则返回true
if (conn.isClosed() || !conn.isValid(3)) {
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}
/**
* conn 既不是 null 且也没有关闭 ,且 isValid 返回 true,说明是可以使用的 (返回false)
*/
return false;
} else {
return true;
}
}
/**
* 设置是否自动提交事务
**/
public void transaction() {
try {
conn.setAutoCommit(autoCommit);
} catch (SQLException e) {
System.out.println("设置事务的提交方式为 : " + (autoCommit ? "自动提交" : "手动提交") + " 时失败: " + e.getMessage());
}
}
/**
* 提交事务
*/
private void commit(Connection c) {
if (c != null && !autoCommit) {
try {
c.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
MySQLDataSource.java
package com.framework.betterorm.Datesource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class MySQLDataSource extends AbstractDataBaseOperationFactory {
@Override
public Connection connect() {
if (invalid()) {
try {
//载入数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//建立连接
conn = DriverManager.getConnection(url, username, password);
System.out.println("Mysql 已连接");
} catch (SQLException e) {
System.out.println("建立 " + conn + " 数据库连接失败 , " + e.getMessage());
} catch (ClassNotFoundException e) {
System.out.println("MySql驱动加载失败:" + e.getMessage());
}
}
return conn;
}
}
其他数据库相关类如下
OracleDataSource.java
package com.framework.betterorm.Datesource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class OracleDataSource extends AbstractDataBaseOperationFactory {
@Override
public Connection connect() {
if (invalid()) {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
//建立连接
conn = DriverManager.getConnection(url, username, password);
System.out.println("Mysql 已连接");
} catch (SQLException e) {
System.out.println("建立 " + conn + " 数据库连接失败 , " + e.getMessage());
} catch (ClassNotFoundException e) {
System.out.println("Oracle驱动加载失败:" + e.getMessage());
}
}
return conn;
}
}
获取conn对象
当有不同的数据库事我们需要大量的的选择判断,去决定将要实例化的类。在这里我们使用策略模式+单例模式+java反射机制去决定实例化那个类
定义数据库类型的枚举
DataBaseTypeEnum.java
package com.framework.betterorm.Datesource;
/**
* @author 王彪
* @date 2019.5.28
* 数据库类型
*/
public enum DataBaseTypeEnum {
/**
* mysql
*/
MYSQL("mysql", "com.framework.betterorm.Datesource.MySQLDataSource"),
/**
* SQLServer
*/
MSSQL("sqlserver", "com.framework.betterorm.Datesource.MsSQLDatasource"),
/**
* oracle
*/
oracle("oracle", "com.framework.betterorm.Datesource.OracleDataSource");
/**
* 数据库类型
*/
private String type;
/**
* 对应操作的实体类
*/
private String clazz;
DataBaseTypeEnum(String type, String clazz) {
this.type = type;
this.clazz = clazz;
}
public String getType() {
return type;
}
public String getClazz() {
return clazz;
}
}
定义单例模式类
CommonSingleton.java
package com.framework.betterorm.common;
import com.framework.betterorm.session.SqlType;
import java.util.HashMap;
import java.util.Map;
public class CommonSingleton {
/**
* 数据库操作类型Map
*/
private static Map<String, String> sqlTypeMap = new HashMap<>();
static {
for (SqlType sqlType : SqlType.values()) {
sqlTypeMap.put(sqlType.getAnnotation(), sqlType.getMethod());
}
}
private CommonSingleton() {
}
public static CommonSingleton getInstance() {
return CommonSingleton.SingletonInstance.instance;
}
/**
* 根据注解取得对应的操作方法
*/
public String sqlTypeStratgy(String annotation) {
return sqlTypeMap.get(annotation);
}
private static class SingletonInstance {
static CommonSingleton instance = new CommonSingleton();
}
}
定义策略模式类
此类就只有一个方法,根据配置文件去实例化相关类然后去实例化connection
package com.framework.betterorm.common;
import com.framework.betterorm.Datesource.DataBaseTypeEnum;
import com.framework.betterorm.session.SqlType;
import java.util.HashMap;
import java.util.Map;
public class CommonSingleton {
/**
* 数据库类型map
*/
private static Map<String, String> dataBaseTypeMap = new HashMap<>();
static {
for (DataBaseTypeEnum dataBaseTypeEnum : DataBaseTypeEnum.values()) {
dataBaseTypeMap.put(dataBaseTypeEnum.getType(), dataBaseTypeEnum.getClazz());
}
}
private CommonSingleton() {
}
public static CommonSingleton getInstance() {
return CommonSingleton.SingletonInstance.instance;
}
/**
* 根据数据库类型取得对应操作类
*/
public String dataBaseOperateStrategy(String type) {
return dataBaseTypeMap.get(type);
}
private static class SingletonInstance {
static CommonSingleton instance = new CommonSingleton();
}
}
此时一个Connection,对象就实例化完成。可以通过此对象去进行操作数据库了。
配置文件如下:
DataBaseConfig.yml
Datasource:
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/test?useSSL=true&serverTimezone=GMT&characterEncoding=utf8
# url: jdbc:sqlserver://localhost:1433;databaseName=test
#url: jdbc:postgresql://localhost/dbname
#url: jdbc:db2://127.0.0.1:50000/dbname
#url: jdbc:sybase:Tds:localhost:5007/dbname
#url: jdbc:oracle:thin:@127.0.0.1:1521:test
autoCommit: false
读取此文件的相关类如下
package com.framework.betterorm.utils;
import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Map;
public class YamlHelper {
public static Map<String, Object> fileRead(String filePath) {
Yaml yaml = new Yaml();
File file = new File(filePath);
try {
if (yaml.load(new FileInputStream(file)) != null) {
return yaml.load(new FileInputStream(file));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
}