模拟Hibernate创建表(注解反射实现):根据javaBean上的注解创建表,并封装增删改查功能

以前学习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);
    }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值