ORM框架

1.ORM简介

  • ORM是对象关系映射(Object-Relational Mapping)的缩写
  • 就是把数据库中的表映射为java的类,表中的记录映射为java的对象,列映射为java类中的属性
  • 该框架可以在不写SQL语句的前提下完成对单表的CRUD操作

需要使用的技术:泛型 注解 反射 JDBC技能

2.创建maven工程并引入相关依赖

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>
    </dependencies>

3.创建一个连接数据库的工具类

db.properties

jdbc.driverName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root
DbUtil.java
package com.wqg.util;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;


public class DbUtil {
    //硬编码放入属性文件db.properties
    private static String driverName = "";
    private static String url = "";
    private static String username = "";
    private static String password = "";

    static {
        //静态代码块。----随着类的加载而被加载,而且只会被加载一次。
        try {
            InputStream inputStream = ClassLoader.getSystemResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(inputStream);
            driverName = properties.getProperty("jdbc.driverName");
            url = properties.getProperty("jdbc.url");
            username = properties.getProperty("jdbc.username");
            password = properties.getProperty("jdbc.password");
        } catch (Exception e) {
            System.out.println("名字为db.properties的属性文件不存在");
            e.printStackTrace();
        }
    }

    //获取连接对象
    public static Connection getConnection() throws Exception {
        Class.forName(driverName);
        Connection connection = DriverManager.getConnection(url, username, password);
        return connection;
    }

    //关闭资源
    public static void closeAll(Connection connection, PreparedStatement ps, ResultSet rs) {
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (ps != null) {
                ps.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (connection != null) {
                connection.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.自定义注解

(1).自定义主键注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableId {
    String value() default "id"; //主键名默认id  //使用此注解标记主键,默认自增,数据库不是自增不能使用
}

(2).自定义属性注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableField {
    String value();
}
//解决列名与属性名不一致的注解 (实体类与数据库名不一致)

(3).自定义表名注解

@Target(ElementType.TYPE) //只能用在类上
@Retention(RetentionPolicy.RUNTIME) //运行时有效
public @interface TableName { 
    String value();
}

5.创建一个父类BaseDao

一个子类DAO继承BaseDao类后,无需再写任何sql语句,而就可以完成单表的crud操作。

比如: StudentDao extends BaseDao 

BaseDao对所有单表CRUD操作都能通用。

5.1.编写通用的添加操作

package com.wqg.dao;

import com.wqg.annotation.TableField;
import com.wqg.annotation.TableId;
import com.wqg.annotation.TableName;
import com.wqg.util.DbUtil;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.List;



public class BaseDao<T> {

    //添加操作
    //insert into 表名(列名,列名....) values(值,值....)
    public int insert(T t) throws Exception {

        StringBuffer sql = new StringBuffer("insert into ");
        //根据对象获取Class反射类
        Class<?> aClass = t.getClass();
        //获取反射类上的注解对象
        TableName annotation = aClass.getAnnotation(TableName.class);
        //获取表名
        String tableName = aClass.getSimpleName();
        if (annotation != null) {
            tableName = annotation.value();
        }
        sql.append(tableName); //表名拼接SQL上

        //获取列名
        Field[] declaredFields = aClass.getDeclaredFields();
        //存放列名
        List<String> columns = new ArrayList<>();
        //列值
        List<String> values = new ArrayList<>();
        for (Field field : declaredFields) {
            String name = field.getName();//属性名(列名)

            TableId annotation2 = field.getAnnotation(TableId.class);
            if (annotation2 != null || name.equals("id")) {
                continue;
            }

            TableField annotation1 = field.getAnnotation(TableField.class);
            if (annotation1 != null) {
                name = annotation1.value(); //注解的value值
            }
            field.setAccessible(true);
            Object o = field.get(t);//获取属性对应的值
            columns.add(name);
            values.add("'" + o + "'");
        }
        //列名
        String columnNames = columns.toString().replace("[", "(").replace("]", ")");
        //列值
        String columnValues = values.toString().replace("[", "(").replace("]", ")");
        //列名和列值拼接SQL上
        sql.append(columnNames);
        sql.append(" values ");
        sql.append(columnValues);

        System.out.println(sql);
        //执行SQL
        Connection connection = DbUtil.getConnection();
        PreparedStatement ps = connection.prepareStatement(sql.toString());
        int i = ps.executeUpdate();
        return i;
    }


}

 5.2.编写通用的修改操作

 //修改操作
    //update 表名 set 列名 = 值 , 列名 = 值..... where 主键列 = 主键值
    public int update(T t) throws Exception {
        StringBuffer sql = new StringBuffer("update ");
        //获取实体类的反射类
        Class<?> aClass = t.getClass();
        //获取反射类上指定的注解对象
        TableName annotation = aClass.getAnnotation(TableName.class);
        String tableName = aClass.getSimpleName();
        if (annotation != null) {
            tableName = annotation.value();
        }
        sql.append(tableName + " set ");
        //获取所有的Field
        Field[] declaredFields = aClass.getDeclaredFields();
        String where = " where ";
        for (Field field : declaredFields) {
            field.setAccessible(true);
            String name = field.getName();
            TableId tableId = field.getAnnotation(TableId.class);
            if (name.equals("id")) {
                where = where + " id='" + field.get(t) + "'";
                continue;
            }
            if (tableId != null) {
                where = where + tableId.value() + " = '" + field.get(t) + "'";
                continue;
            }
            TableField tableField = field.getAnnotation(TableField.class);
            if (tableField != null) {
                name = tableField.value();
            }
            String value = "'" + field.get(t) + "'";
            sql.append(name + "=" + value + ",");
        }

        String sql2 = sql.toString().substring(0, sql.length() - 1) + where;
        System.out.println(sql2);

        //执行SQL
        Connection connection = DbUtil.getConnection();
        PreparedStatement ps = connection.prepareStatement(sql2);
        int i = ps.executeUpdate();
        return i;

    }

 5.3.编写通用的删除操作

//为获取表名
  // 总体而言,这段代码的目的是通过反射获取当前类继承的父类的泛型参数类型,并将其存储在aCl变量中。
    // 具体来说,这段代码适用于继承了BaseDao的子类,通过子类的构造函数获取泛型参数的类型。
  
  Class<T> clazz; //泛型的反射类
    public BaseDao(){
        //获取BaseDao子类的反射类对象
        Class<? extends BaseDao> aClass = this.getClass();
        //获取当前Dao子类的父类的反射类
        ParameterizedType parameterizedType = (ParameterizedType) aClass.getGenericSuperclass();

        //得到父类反射类上的泛型的反射类
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        clazz = (Class<T>) actualTypeArguments[0];
    }


    //删除操作
    //delete from 表名 where 主键列=主键值
    public int delete(Object id) throws Exception{
        StringBuffer sql = new StringBuffer("delete from ");
        TableName annotation = clazz.getAnnotation(TableName.class);
        String tableName = clazz.getSimpleName();
        if (annotation != null){
            tableName=annotation.value();
        }
        sql.append(tableName+" where ");

        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields){
            TableId tableId = field.getAnnotation(TableId.class);
            if (tableId != null){
                sql.append(tableId.value()+"='"+id+"'");
                continue;
            }
        }
        //执行SQL
        Connection connection = DbUtil.getConnection();
        PreparedStatement ps = connection.prepareStatement(sql.toString());
        int i = ps.executeUpdate();
        return i;
    }

 5.4.编写通用的单个查询操作

   //查询(根据主键单个查询)
    //select * from 表名 where 主键列=值
     //定义一个泛型方法,根据传入的id查询数据并返回
    public T selectById(Object id) throws Exception {
        //创建一个StringBuffer对象,并添加查询语句
        StringBuffer sql = new StringBuffer("select  *  from  ");
        //获取当前类中的@TableName注解
        TableName annotation = clazz.getAnnotation(TableName.class);
        //获取当前类的简单名称
        String tableName = clazz.getSimpleName();
        //如果@TableName注解不为空,则将其值赋给tableName
        if (annotation != null) {
            tableName = annotation.value();
        }
        //将tableName添加到sql语句中,并添加查询条件
        sql.append(tableName + "  where  ");
        //获取当前类中的所有属性
        Field[] fields = clazz.getDeclaredFields();
        //遍历属性数组
        for (Field field : fields) {
            //获取当前属性的@TableId注解
            TableId tableId = field.getAnnotation(TableId.class);
            //如果@TableId注解不为空,则将其值添加到sql语句中
            if (tableId != null) {
                sql.append(tableId.value() + "='" + id + "'");
                continue;
            }
        }
        //执行SQL语句
        Connection connection = DbUtil.getConnection();
        PreparedStatement ps = connection.prepareStatement(sql.toString());
        ResultSet resultSet = ps.executeQuery();
        //定义一个泛型变量t,并初始化为null
        T t = null;
        //遍历结果集
        while (resultSet.next()) {
            //创建一个新的实例
            t = clazz.newInstance();
            //获取当前实例中的所有属性
            Field[] declaredFields = clazz.getDeclaredFields();
            //遍历属性数组
            for (Field field : declaredFields) {
                //设置属性可访问
                field.setAccessible(true);
                //获取属性名称
                String name = field.getName();
                //获取当前属性的@TableField注解
                TableField tableField = field.getAnnotation(TableField.class);
                //如果@TableField注解不为空,则将其值赋给name
                if (tableField != null) {
                    name = tableField.value();
                }
                //获取当前属性的@TableId注解
                TableId tableId = field.getAnnotation(TableId.class);
                //如果@TableId注解不为空,则将其值赋给name
                if (tableId != null) {
                    name = tableId.value();
                }
                //获取结果集中指定列的值
                Object v = resultSet.getObject(name);
                //将属性值赋给实例
                field.set(t, v);
            }
        }
        //返回实例
        return t;
    }

 5.5.编写通用的查询所有操作

  //查询所有
    //select * from 表名
    public List<T> findAll() throws Exception {

        StringBuffer stringBuffer = new StringBuffer("select * from ");

        List<T> list = new ArrayList<>(); //定义一个泛型集合,用来存储查找到的结果
        Connection connection = null; //定义连接对象,初始值为null
        PreparedStatement ps = null; //定义预编译对象,初始值为null
        ResultSet rs = null; //定义结果集对象,初始值为null

        //获取表名
        TableName tableName = (TableName)
                clazz.getAnnotation(TableName.class);
        if (tableName == null) {
            throw new RuntimeException("未使用TableName注解标记表名");
        }
        String name = tableName.value(); //拿到表名
        stringBuffer.append(name);
        try {
            connection = DbUtil.getConnection(); //通过工具类获取数据库连接
            ps = connection.prepareStatement(stringBuffer.toString()); //预编译SQL语句
            rs = ps.executeQuery(); //执行查询语句,获取结果集
            while (rs.next()) { //遍历结果集
                T t = (T) clazz.newInstance(); //使用反射机制创建一个对象实例
                Field[] declaredFields = clazz.getDeclaredFields(); //获取反射类中所有的属性对象
                for (Field field : declaredFields) { //遍历所有属性对象
                    field.setAccessible(true); //设置属性可以访问
                    TableId tableId = field.getAnnotation(TableId.class); //获取属性上的主键注解
                    if (tableId != null) { //如果主键注解不为空
                        field.set(t, rs.getObject(tableId.value())); //设置属性值为结果集中对应主键列的值
                    } else { //如果该属性不是主键字段
                        TableField tableField = field.getAnnotation(TableField.class); //获取除主键外的属性上的TableField注解
                        if (tableField != null) { //如果TableField注解不为空
                            field.set(t, rs.getObject(tableField.value())); //设置属性值为结果集中对应列的值
                        } else { //如果该属性既不是主键字段,也没有TableField注解
                            field.set(t, rs.getObject(field.getName()));  //设置属性值为结果集中对应列的值,列名和属性名一致
                        }
                    }
                }
                list.add(t); //将对象添加到泛型集合中
            }
        } catch (Exception e) { //捕获异常
            e.printStackTrace(); //打印异常栈信息
        } finally { //无论是否发生异常,都执行finally中的代码
            //  DbUtil.closeAll(rs,ps,connection); //关闭结果集、预编译对象、连接
            DbUtil.closeAll(connection, ps, rs);
        }
        return list; //返回泛型集合
    }

6.导出jar包(存储ORM框架)

 7.导入ORM框架的jar包

在其他工程中使用ORM框架,只需要导入jar包,配置为库

配置相关依赖和db.properties文件(上面第3条有)

 

8.测试ORM的CRUD

导入ORM的jar包,配置pom依赖,配置为库,配置db.properties文件...

数据库表:

 创建Student.java

@TableName("tbl_student")
public class Student {

    @TableId(value = "sid")
    private Integer sid;

    @TableField(value = "sname")
    private String sName;

    @TableField(value = "class_id")
    private Integer classId;


    public Student() {
    }

    public Student(Integer sid, String sName, Integer classId) {
        this.sid = sid;
        this.sName = sName;
        this.classId = classId;
    }

    /**
     * 获取
     * @return sid
     */
    public Integer getSid() {
        return sid;
    }

    /**
     * 设置
     * @param sid
     */
    public void setSid(Integer sid) {
        this.sid = sid;
    }

    /**
     * 获取
     * @return sName
     */
    public String getSName() {
        return sName;
    }

    /**
     * 设置
     * @param sName
     */
    public void setSName(String sName) {
        this.sName = sName;
    }

    /**
     * 获取
     * @return classId
     */
    public Integer getClassId() {
        return classId;
    }

    /**
     * 设置
     * @param classId
     */
    public void setClassId(Integer classId) {
        this.classId = classId;
    }

    public String toString() {
        return "Student{sid = " + sid + ", sName = " + sName + ", classId = " + classId + "}";
    }
}

创建StudentDao.java

public class StudentDao extends BaseDao<Student> {
}

创建Test.java测试CRUD

public class Test {
    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        //查询所有
        //System.out.println(studentDao.findAll());
        //根据id查询单个
        //System.out.println(studentDao.selectById(1));
        //增加
        //studentDao.insert(new Student(6,"马保",1));
        //修改
        //studentDao.update(new Student(1,"LDH66",2));
        //删除
        //studentDao.delete(5);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值