一个简单的持久层框架
1. 简单概述
1.1 什么是持久层框架
与数据库交互的一层称为持久层(一般指的是dao层),用于完成orm操作。
orm指什么?
o:(Object对象) r:(relative关系) m:(mapping映射)。
实体类—数据库表 属性–表的字段 实体类对象–一条记录 集合—表中多条记录。
1.2 需要用到的技术
java+mysql+反射+自定义注解+泛型+jdbc
2. 正文
2.1前置准备
创建一个maven的java工程
引入依赖jar
<dependencies>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- 阿里巴巴druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.16</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
</dependency>
</dependencies>
创建数据源的属性文件
#配置数据源信息
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/数据库名?serverTimezone=Asia/Shanghai
username=root
password=你的密码
2.2 创建DbUtil工具类
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
public class DbUtil {
//数据源对象
private static DataSource dataSource;
//静态代码块中---只会加载一次
static {
try {
//创建一个属性对象
Properties properties = new Properties();
//加载属性文件
InputStream inputStream = DbUtil.class.getClassLoader().getResourceAsStream("db.properties");
properties.load(inputStream);
//获取连接池对象
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取链接对象
public static Connection getConnection() throws Exception{
Connection conn=dataSource.getConnection();
return conn;
}
//释放资源
public static void closeAll(Connection conn, PreparedStatement ps, ResultSet rs) {
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
2.3 注解文件
1. 表名的注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableName {
//表示表的名称
String value();
}
2. 列名的注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableField {
String value();
}
3. 主键的注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableId {
String value() default "id";
}
使用场景:如果实体类的表名,属性名和数据库的表名,列名不相同,使用注解
2.4 通用的添加功能
//通用添加功能 sql语句: insert into 表名(列名...) values(值...)
public int insert(T t) throws Exception {
//创建一个sql字符串
StringBuffer sql = new StringBuffer("insert into ");
//获取实体类的反射类
Class<?> aClass = t.getClass();
//获取表名
String tableName = aClass.getSimpleName();//实体类的名称
TableName annotation = aClass.getAnnotation(TableName.class);
if(annotation!=null){
tableName=annotation.value();
}
sql.append(tableName);
//获取所有的列名--对应的属性名
List<String> columnNames = new ArrayList<>();
List<Object> values = new ArrayList<>();
//获取所有的属性对象
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
//获取属性名
String name = field.getName();
//获取属性名的注解
TableId tableIdAnnotation = field.getAnnotation(TableId.class);
TableField fieldAnnotation = field.getAnnotation(TableField.class);
if(tableIdAnnotation!=null){
continue;
}
if(fieldAnnotation!=null){
name=fieldAnnotation.value();
}
field.setAccessible(true);
//对象的属性值
Object value = null;
value = field.get(t);
values.add("'"+value+"'");
columnNames.add(name);
}
String replace = columnNames.toString().replace("[", "(").replace("]", ")");
String replace1 = values.toString().replace("[", "(").replace("]", ")");
sql.append(replace+" values "+replace1);
//执行sql语句
System.out.println(sql);
Connection conn = DbUtil.getConn();
PreparedStatement ps = conn.prepareStatement(sql.toString());
int i = ps.executeUpdate();
return i;
}
2.5 通用的修改功能
//通用的修改 sql语句: update 表名 set 列名=值 ... where 主键=id
public int update(T t) throws Exception{
StringBuffer sql = new StringBuffer("update ");
//获取表名
Class<?> aClass = t.getClass();
String tableName = aClass.getSimpleName();
TableName annotation = aClass.getAnnotation(TableName.class);
if(annotation!=null){
tableName=annotation.value();
}
sql.append(tableName+" set ");
String where = " where ";
//获取所有对象
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
//获取属性名
String name = field.getName();
TableId tableIdAnnotation = field.getAnnotation(TableId.class);
TableField fieldAnnotation = field.getAnnotation(TableField.class);
field.setAccessible(true);
Object value = field.get(t);
if(tableIdAnnotation!=null){
String tableIdName = tableIdAnnotation.value();
where+=tableIdName+"='"+value+"'";
continue;
}
if(fieldAnnotation!=null){
name = fieldAnnotation.value();
}
sql.append(name+"='"+value+"',");
}
sql.deleteCharAt(sql.length()-1).append(where);
//执行sql语句
System.out.println(sql);
Connection conn = DbUtil.getConn();
PreparedStatement ps = conn.prepareStatement(sql.toString());
int i = ps.executeUpdate();
return i;
}
2.6 通用的删除功能
private Class<T> clazz;
public BaseDao(){
//this表示子类Dao对象
Class<? extends BaseDao> aClass = this.getClass();
//获取当前子类的父类的反射类
ParameterizedType genericSuperclass = (ParameterizedType) aClass.getGenericSuperclass();
//获取该反射类中的泛型类型
Type actualTypeArgument = genericSuperclass.getActualTypeArguments()[0];
clazz= (Class) actualTypeArgument;
}
//通用的删除操作 sql语句: delete from 表名 where 主键=值
public int deleteById(Object id) throws Exception{
StringBuffer sql=new StringBuffer("delete from ");
String tableName = clazz.getSimpleName();//实体类的名称
TableName annotation = clazz.getAnnotation(TableName.class);
if(annotation!=null){
tableName=annotation.value();
}
sql.append(tableName+" where ");
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
TableId tableId = field.getAnnotation(TableId.class);
if(tableId!=null){
sql.append(tableId.value()+"="+id);
break;
}
}
//执行sql
System.out.println(sql);
Connection conn = DbUtil.getConn();
PreparedStatement ps = conn.prepareStatement(sql.toString());
int i = ps.executeUpdate();
return i;
}
将自己写的框架打包为一个jar,并安装到本地仓库
mvn install:install-file -Dfile=D:\aliyun-java-vod-upload-1.4.7.jar -DgroupId=com.aliyun -DartifactId=aliyun-java-vod-upload -Dversion=1.4.7 -Dpackaging=jar
-Dfile=D:\aliyun-java-vod-upload-1.4.7.jar
:指定要安装的jar文件的路径和文件名。-DgroupId=com.aliyun
:指定要安装的jar文件所属的groupId,通常用于组织依赖。-DartifactId=aliyun-java-vod-upload
:指定要安装的jar文件的artifactId,通常用于识别依赖。-Dversion=1.4.7
:指定要安装的jar文件的版本号。-Dpackaging=jar
:指定要安装的文件类型为jar包。
2.7 通用的根据主键查询对象
public T selectById(Object id) throws Exception{
StringBuffer sql=new StringBuffer("select * from ");
//获取表名
String tableName=clazz.getSimpleName();
TableName annotation = clazz.getAnnotation(TableName.class);
if(annotation!=null){
tableName=annotation.value();
}
sql.append(tableName+" where ");
//获取主键列名
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field:declaredFields){
TableId tableId = field.getAnnotation(TableId.class);
if(tableId!=null){
sql.append(tableId.value()+"="+id);
break;
}
}
//执行sql语句
Connection conn = DbUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(sql.toString());
ResultSet rs = ps.executeQuery();
//封装数据到实体类
while(rs.next()){
T t=clazz.newInstance();
for (Field field:declaredFields){
field.setAccessible(true);
TableField tableField = field.getAnnotation(TableField.class);
TableId tableId = field.getAnnotation(TableId.class);
//获取属性名
String name = field.getName();
if(tableId!=null){
name=tableId.value();
}
if(tableField!=null){
name=tableField.value();
}
//获取数据库中指定列的值
Object v = rs.getObject(name);
//为指定对象的属性赋值
field.set(t,v);
}
return t;
}
return null;
}
2.8 通用的查询所有对象
public List<T> selectAll()throws Exception{
List<T> list=new ArrayList<>();
StringBuffer sql=new StringBuffer("select * from ");
//获取表名
String tableName=clazz.getSimpleName();
TableName annotation = clazz.getAnnotation(TableName.class);
if(annotation!=null){
tableName=annotation.value();
}
sql.append(tableName);
//执行sql语句
Connection conn = DbUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(sql.toString());
ResultSet rs = ps.executeQuery();
Field[] declaredFields = clazz.getDeclaredFields();
//封装数据
while (rs.next()){
T t=clazz.newInstance();
//为实体类的属性赋值
for (Field field:declaredFields){
field.setAccessible(true);
TableField tableField = field.getAnnotation(TableField.class);
TableId tableId = field.getAnnotation(TableId.class);
//获取属性名
String name = field.getName();
if(tableId!=null){
name=tableId.value();
}
if(tableField!=null){
name=tableField.value();
}
//获取数据库中指定列的值
Object v = rs.getObject(name);
//为指定对象的属性赋值
field.set(t,v);
}
list.add(t);
}
return list;
}