以前学习Hibernate框架就有对应的Pojo类映射到数据库(帮我们创建表),然后可以使用反射来模拟一下。
思路:通过反射获取成员变量和类上的注解,判断字段的类型向数据库发sql语句创建表。再封装一些方法来操作数据库,增删改查。不同的对象需要传入对应的对象的class字节码对象,来判断操作那一张表。
主要功能:
1。创建bean,例如创建一个Person类,写上注解
2.创建测试类
运行之后数据库就会创建表,并添加这个对象的数据。
session对象中封装了一些方法:
以下是实现的代码
db.properties文件 (src下的db.properties文件配置数据库的相应信息)
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/myhibernate?serverTimezone=UTC
username=root
password=123456
database=myhibernate
Column注解:
package com.annoction;
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 Column {
//字段
String value();
}
Primarykey注解
package com.annoction;
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 Primarykey {
//设置主键 默认为id
String value() default "id";
}
TableName注解
package com.annoction;
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();
}
Bean类
package com.bean;
import com.annoction.Column;
import com.annoction.Primarykey;
import com.annoction.TableName;
@TableName("person")
public class Person {
@Primarykey("sid")//默认值为id
@Column("sid")
private int id;
@Column("pname")
private String name;
@Column("page")
private int age;
public Person() {
}
public Person(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
DBCon类:
package com.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class DBCon {
private static Properties prop;
private Connection conn;
private ResultSet rs;
private PreparedStatement pstmt;
public DBCon() {
this.conn = getConn();
}
/**
* 加载配置文件
*/
static {
//获取配置文件的属性
prop = new Properties();
InputStream is = DBCon.class.getClassLoader().getResourceAsStream("db.properties");
try {
prop.load(is);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接
*
* @return
*/
public Connection getConn() {
try {
Class.forName(prop.getProperty("driver"));
conn = DriverManager.getConnection(prop.getProperty("url"), prop.getProperty("username"), prop.getProperty("password"));
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
/**
* 封装查询
*
* @param sql
* @param arrs
* @return
*/
public ResultSet doQuery(String sql, Object[] arrs) {
// rs = null;
try {
pstmt = conn.prepareStatement(sql);
for (int i = 0; i < arrs.length; i++) {
pstmt.setObject((i + 1), arrs[i]);
}
rs = pstmt.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
return rs;
}
/**
* 封装增删改
*
* @param sql
* @param arrs
* @return
*/
public int doUpdate(String sql, Object[] arrs) {
int res = 0;
try {
pstmt = conn.prepareStatement(sql);
for (int i = 0; i < arrs.length; i++) {
pstmt.setObject((i + 1), arrs[i]);
}
res = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
return res;
}
/**
* 开启事务
*/
public void OpenTransaction() {
try {
//开启事务
conn.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 提交事务
*/
public void commit() {
try {
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 回滚事务
*/
public void rollback() {
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 关闭资源
*/
public void close() {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Session类:
package com.util;
import com.annoction.Column;
import com.annoction.Primarykey;
import com.annoction.TableName;
import com.myexception.FieldsNoMappingException;
import com.myexception.PrimaryKeyNotFoundExcept;
import com.myexception.TableExistsException;
import com.myexception.TableNameNotFoundException;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class Session {
private DBCon dbc;
public Session() {
//创建session对象时获取以一个Conn对象
this.dbc = new DBCon();
}
/**
* 获取表名的注解
*
* @param clazz 要获取表名的类
* @return 表名称
*/
private String getTableName(Class<?> clazz) {
//获取表名注解
TableName annotation = clazz.getAnnotation(TableName.class);
if (annotation != null)
return annotation.value();
throw new TableNameNotFoundException("请设置在类名上设置表名注解");
}
/**
* 类型转换
*
* @param type
* @return
*/
private String changetype(String type) {
switch (type) {
//判断包装类型
case "int":
case "java.lang.Integer":
type = "int";
break;
case "float":
case "java.lang.Float":
type = "float(10,2)";
break;
case "boolean":
case "java.lang.Boolean":
type = "boolean";
break;
case "char":
case "java.lang.Character":
type = "char";
break;
case "java.lang.Double":
type = "double(12,4)";
break;
case "java.util.Date":
type = "date";
break;
case "java.sql.Timestamp":
type = "timestamp";
break;
case "java.lang.String":
default:
type = "varchar(100)";
}
return type;
}
/**
* 拼写sql
*
* @param clazz
* @return
*/
private String createsql(Class<?> clazz) {
StringBuilder sb = new StringBuilder();
sb.append("create table if not exists `" + getTableName(clazz) + "` (");
Field[] fields = clazz.getDeclaredFields();
String primarykeyName = getPrimarykeyName(clazz);
//设置标记判断是否设置了字段注解
boolean falg = true;
for (Field field : fields) {
//获取字段的主键注解
Primarykey primarykey = field.getAnnotation(Primarykey.class);
if (primarykey != null) {
//获取对应的字段的值
String value = primarykey.value();
//获取主键的类型
AnnotatedType an = field.getAnnotatedType();
String type = changetype(an.toString());
sb.append(value).append(" ").append(type).append(" primary key auto_increment,");
}
//获取字段注解
Column column = field.getAnnotation(Column.class);
if (column != null) {
//判断字段是否为主键注解是就跳过
if (!column.value().equals(primarykeyName)) {
//更改标记
falg = false;
//获取对应的字段的注解值
String value = column.value();
//获取对应字段的类型
AnnotatedType an = field.getAnnotatedType();
String type = changetype(an.toString());
sb.append(value).append(" ").append(type).append(",");
}
}
}
String sql = sb.substring(0, sb.length() - 1).concat(");");
//System.out.println(sql);
if (falg) throw new FieldsNoMappingException("字段没有设置注解");
return sql;
}
/**
* 创建表
*
* @param clazz
*/
private void createTable(Class<?> clazz) {
if (!isExists(clazz)) {
//不存在表则创建
String sql = createsql(clazz);
int create = dbc.doUpdate(sql, new Object[]{});
if (create >= 0) {
//System.out.println("表创键成功!");
}
} else {
//若存在表抛异常
throw new TableExistsException();
}
}
/**
* 用于判断表是否存在
*
* @param clazz
* @return
*/
private boolean isExists(Class<?> clazz) {
//先判断对应的表是否存在
String table = "show tables like '" + getTableName(clazz) + "'";
ResultSet rs = dbc.doQuery(table, new Object[]{});
boolean exists = false;
try {
exists = rs.next();
} catch (SQLException e) {
e.printStackTrace();
}
return exists;
}
/**
* 添加对象
*
* @param e 要添加的对象
* @param <E> 类型
*/
public <E> void add(E e) {
Class<?> clazz = e.getClass();
if (isExists(clazz)) {
//获取对象的类的表名称
String tablename = getTableName(clazz);
StringBuilder sb = new StringBuilder();
sb.append("insert into ").append("`" + tablename + "`").append(" ( ");
//获取全部字段
Field[] fields = clazz.getDeclaredFields();
Object[] objs = new Object[fields.length];
int index = 0;
//定义一个标记
boolean flag = true;
for (Field field : fields) {
field.setAccessible(true);
//获取对象对应字段的值
Object obj = null;
try {
obj = field.get(e);
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
objs[index++] = obj;
//获取表的主键名
String primarykeyName = getPrimarykeyName(clazz);
//获取其他字段的注解
Column column = field.getAnnotation(Column.class);
if (column != null) {
//判断是否添加重复主键的值
if (column.value().equals(primarykeyName)) {
//获取对象的主键值
int primary = 0;
try {
primary = (int) field.get(e);
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
Object value = queryByid(primary, clazz);
if (value != null) throw new RuntimeException("不能添加重复主键的值!");
}
if (flag) {
sb.append(column.value());
flag = false;
} else {
sb.append(",").append(column.value());
}
}
}
sb.append(") values (");
//拼写占位符
for (int i = 0; i < fields.length; i++) {
if (i == fields.length - 1) sb.append("?);");
else sb.append("?,");
}
String sql = sb.toString();
//System.out.println(sql);
int res = dbc.doUpdate(sql, objs);
if (res > 0) {
System.out.println("添加成功!");
}
} else {
createTable(clazz);
}
}
/**
* 根据主键删除数据
*
* @param id
* @param clazz
* @param <E>
*/
public <E> void delete(int id, Class<?> clazz) {
if (isExists(clazz)) {
StringBuilder sb = new StringBuilder();
sb.append("delete from").append("`" + getTableName(clazz) + "`").append("where ").append(getPrimarykeyName(clazz)).append("= ?");
String sql = sb.toString();
int delete = dbc.doUpdate(sql, new Object[]{id});
if (delete > 0) {
System.out.println("删除成功!");
}
} else {
throw new RuntimeException("不存在" + getTableName(clazz) + "表");
}
}
/**
* 根据对象的主键更新对象内容
*
* @param e
* @param <E> 要添加的对象
*/
public <E> void update(E e) {
Class<?> clazz = e.getClass();
//判断表是否存在
if (isExists(clazz)) {
StringBuilder sb = new StringBuilder();
sb.append("update ").append("`" + getTableName(clazz) + "`").append(" set ");
//获取对象的属性值
Field[] fields = clazz.getDeclaredFields();
Object[] objs = new Object[fields.length];
int index = 0;
String PrimarykeyName = getPrimarykeyName(clazz);
for (Field field : fields) {
field.setAccessible(true);
//获取字段注解
Column column = field.getAnnotation(Column.class);
if (column != null) {
if (!column.value().equals(PrimarykeyName)) {
sb.append(column.value() + " = ?,");
try {
objs[index++] = field.get(e);
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
}
}
//获取主键注解
Primarykey primarykey = field.getAnnotation(Primarykey.class);
if (primarykey != null) {
//获取主键的值
try {
objs[fields.length - 1] = field.get(e);
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
}
}
String sql = sb.substring(0, sb.length() - 1).concat(" where " + PrimarykeyName + "= ?;");
//System.out.println(sql);
int i = dbc.doUpdate(sql, objs);
if (i > 0) {
System.out.println("修改成功!");
} else {
System.out.println("没有该id的数据");
}
} else {
throw new RuntimeException("不存在该表");
}
}
/**
* 获取字段上所有的字段注解
*
* @param clazz 要获取字段的类
* @return
*/
private List<String> getColumn(Class<?> clazz) {
ArrayList<String> list = new ArrayList<>();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Column column = field.getAnnotation(Column.class);
if (column != null) {
list.add(column.value());
}
}
return list;
}
/**
* 获取主键名称
*
* @param clazz 要获取主键的类
* @return
*/
private String getPrimarykeyName(Class<?> clazz) {
String name;
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
Primarykey primarykey = field.getAnnotation(Primarykey.class);
if (primarykey != null) {
name = primarykey.value();
return name;
}
}
throw new PrimaryKeyNotFoundExcept("没有找到主键注解");
}
/**
* 获取对应类的全部数据返回list
*
* @param clazz
* @return
*/
public ArrayList<Object> queryAlltolist(Class<?> clazz) {
if (isExists(clazz)) {
String sql = "select * from " + getTableName(clazz) + ";";
ArrayList list = new ArrayList();
//获取无参构造
Constructor<?> constructor = null;
try {
constructor = clazz.getDeclaredConstructor();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
Field[] fields = clazz.getDeclaredFields();
ResultSet rs = dbc.doQuery(sql, new Object[]{});
try {
while (rs.next()) {
//创建一个对象
Object obj = constructor.newInstance();
for (Field field : fields) {
field.setAccessible(true);
field.set(obj, rs.getObject(field.getAnnotation(Column.class).value()));
}
list.add(obj);
}
} catch (SQLException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return list;
} else throw new RuntimeException("不存在" + getTableName(clazz) + "表");
}
/**
* 根据主键查询对象类的数据
*
* @param id
* @param clazz
* @return
*/
public Object queryByid(int id, Class<?> clazz) {
if (isExists(clazz)) {
String sql = "select * from " + getTableName(clazz) + " where " + getPrimarykeyName(clazz) + "=?";
ResultSet rs = dbc.doQuery(sql, new Object[]{id});
//判断该id主键是否有,若没有则返回null
boolean flag = false;
try {
flag = rs.next();
} catch (SQLException e) {
e.printStackTrace();
}
if (!flag) return null;
Constructor<?> constructor = null;
try {
constructor = clazz.getDeclaredConstructor();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
Field[] fields = clazz.getDeclaredFields();
Object obj = null;
try {
obj = constructor.newInstance();
while (rs.next()) {
//遍历字段赋值
for (Field field : fields) {
field.setAccessible(true);
Column column = field.getAnnotation(Column.class);
//创建一个对象
field.set(obj, rs.getObject(column.value()));
}
}
} catch (SQLException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
return obj;
} else throw new RuntimeException("不存在" + getTableName(clazz) + "表");
}
/**
* 开启事务
*/
public void OpenTransaction() {
dbc.OpenTransaction();
}
/**
* 提交事务
*/
public void commit() {
dbc.commit();
}
/**
* 回滚事务
*/
public void rollback() {
dbc.rollback();
}
/**
* 释放资源
*/
public void close() {
dbc.close();
}
}
还有一些自定义的异常类:
package com.myexception;
public class DBConNotConnectionException extends RuntimeException{
public DBConNotConnectionException(String message) {
super(message);
}
}
package com.myexception;
public class FieldsNoMappingException extends RuntimeException{
public FieldsNoMappingException(String message) {
super(message);
}
}
package com.myexception;
public class PrimaryKeyNotFoundExcept extends RuntimeException{
public PrimaryKeyNotFoundExcept(String message) {
super(message);
}
}
package com.myexception;
public class TableExistsException extends RuntimeException{
private static final String ERRMESS="该表已经存在!";
public TableExistsException() {
super(ERRMESS);
}
}
package com.myexception;
public class TableNameNotFoundException extends RuntimeException {
public TableNameNotFoundException(String message) {
super(message);
}
}