一路走到ORM框架都经历了什么(下)

简介: 一路走到ORM框架都经历了什么

创建JdbcTemplate,利用DataSource与数据库直接交互,实现通用方法

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
 * 根据资源获取连接,执行SQL,结果集
 */
public abstract class JdbcTemplate extends MyDataSource {
    protected static Connection connection;
    protected static PreparedStatement preparedStatement;
    protected ResultSet resultSet;
    //查询
    protected <T> List<T> executeQuery(String sql , RowMapper<T> rowMapper) throws Exception {
        preparedStatement = preparedStatement(sql);
        resultSet = preparedStatement.executeQuery();
        List<T> list = resultSet(resultSet, rowMapper);
        close();
        return list;
    }
    //更新
    protected int executeUpdate(String sql) throws SQLException {
        preparedStatement = preparedStatement(sql);
        int i = preparedStatement.executeUpdate();
        close();
        return i;
    }
    protected void execute(String sql){
        try {
            preparedStatement = preparedStatement(sql);
            preparedStatement.execute();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //close();
        }
    }
    //获取链接
    private Connection getConnection() throws SQLException {
        if (connection == null){
            connection = this.dataSource.getConnection();
        }
        return connection;
    }
    //预执行sql
    private PreparedStatement preparedStatement(String sql) throws SQLException {
        connection = getConnection();
        if (preparedStatement == null){
            preparedStatement = connection.prepareStatement(sql);
        }
        return preparedStatement;
    }
    //结果集
    private <T> List<T> resultSet(ResultSet resultSet , RowMapper<T> rowMapper) throws Exception {
        List<T> list = new ArrayList<>();
        while (resultSet.next()){
            list.add(rowMapper.mapRow(resultSet));
        }
        return list;
    }
    //关闭
    private void close(){
        try {
            if (connection != null) {
                connection.close();
            }
            if (preparedStatement != null) {
                preparedStatement.close();
            }
            if (this.resultSet != null) {
                this.resultSet.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

其中结果集的映射:RowMapper,这里写的接口,当使用的时候,使用匿名内部类操作

public interface RowMapper<T> {
    T mapRow(ResultSet resultSet) throws Exception;
}

用户面向对象编程,不写SQL,所以我们底层需要反射获取对象的参数,然后解析拼接为SQL

这里我们将反射对象的通用操作封装

public abstract class BaseSQLBuilder {
    protected String tableName; //表名
    protected String primaryKeyName; //主键名
    protected final String SELECT = "select ";
    protected final String FROM = " from ";
    protected final String WHERE = " where ";
    protected final String AND = " and ";
    protected final String IN = " IN ";
    protected final String UPDATE = " UPDATE ";
    protected final String SET = " SET ";
    protected final String VALUES = " VALUES ";
    protected final String OR = " OR ";
    protected final String DELETE = " DELETE ";
    protected final String INSERT = " INSERT ";
    protected final String INTO = " INTO ";
    protected StringBuilder sqlBuilder = new StringBuilder();
    protected void getTableName(Object obj){
        Table table = obj.getClass().getAnnotation(Table.class);
        tableName = table.value();
        if (Objects.equals(tableName, "")) {
            // 全类名拆分
            tableName = StringUtil.getLastStr(obj.getClass().getName());
        }
    }
    protected void getPrimaryKey(Field field){
        PrimaryKey primaryKey = field.getAnnotation(PrimaryKey.class);
        primaryKeyName = primaryKey.value();
        if (Objects.equals(primaryKeyName, "")) {
            primaryKeyName = StringUtil.getLastStr(field.getClass().getName());
        }
    }
    protected boolean hasPrimaryKey(Field field){
        PrimaryKey primaryKey = field.getAnnotation(PrimaryKey.class);
        return primaryKey != null;
    }
    protected String getField(String fieldStr){
        return "get" + fieldStr.substring(0, 1).toUpperCase() + fieldStr.substring(1);
    }
    protected Field[] getFields(Object obj){
        return obj.getClass().getDeclaredFields();
    }
}

这里我们只以查询为例

public class QuerySQLBuilder extends BaseSQLBuilder {
    public String querySql(Object t) throws Exception {
        // 获取操作表名
        getTableName(t);
        // SQL拼接
        sqlBuilder.append(SELECT + "*" + FROM).append(tableName).append(WHERE + " 1=1 ");
        for (Field field : getFields(t)) {
            String fieldStr = StringUtil.getLastStr(field.toString());
            Object value = t.getClass().getMethod(getField(fieldStr)).invoke(t);
            if (!"".equals(value) && null != value) {
                sqlBuilder.append(AND).append(fieldStr).append("=").append("'").append(value).append("'");
            }
        }
        return sqlBuilder.toString();
    }
}

我们将QuerySQLBuilder。。。其他Builder封装到一个工厂类中,进行获取

public class SQLBuilderInstanceFactory {
    static QuerySQLBuilder queryBuilder = null;
    static SaveSQLBuilder saveBuilder = null;
    static UpdateSQLBuilder updateBuilder = null;
    static DeleteSQLBuilder deleteSQLBuilder = null;
    public static QuerySQLBuilder getQueryBuilder(){
        if (queryBuilder == null) {
            queryBuilder = new QuerySQLBuilder();
        }
        return queryBuilder;
    }
    public static SaveSQLBuilder getSaveBuilder(){
        if (saveBuilder == null) {
            saveBuilder = new SaveSQLBuilder();
        }
        return saveBuilder;
    }
    public static UpdateSQLBuilder getUpdateBuilder(){
        if (updateBuilder == null) {
            updateBuilder = new UpdateSQLBuilder();
        }
        return updateBuilder;
    }
    public static DeleteSQLBuilder getDeleteSQLBuilder(){
        if (deleteSQLBuilder == null) {
            deleteSQLBuilder = new DeleteSQLBuilder();
        }
        return deleteSQLBuilder;
    }
}

定义查询接口

public interface IQuery<T> {
    List<T> query(T t) throws Exception;
}

查询具体实现类

public class Query<T> extends JdbcTemplate implements IQuery<T> {
    @Override
    public List<T> query(T t) throws Exception {
        // 解析出的SQL
        String sql = SQLBuilderInstanceFactory.getQueryBuilder().querySql(t);
        System.out.println("sql  "+sql);
        Field[] fields = t.getClass().getDeclaredFields();
        // 执行SQL
        return executeQuery(sql, new RowMapper<T>() {
            @Override
            public T mapRow(ResultSet resultSet) throws Exception {
                for (Field field : fields) {
                    String getField = StringUtil.getSetMethod(StringUtil.getLastStr(field.toString()));
                    Object object = resultSet.getObject(StringUtil.getLastStr(field.toString()), field.getType());
                    t.getClass().getMethod(getField,field.getType()).invoke(t,object);
                }
                return t;
            }
        });
    }
}

现在大体上的代码都已经实现了,我们测试一下

public class Client {
    public static void main(String[] args) throws Exception {
        User user = new User();
        user.setAddress("china");
        // 查询操作
        Query<User> userQuery = new Query<>();
        List<User> userList = userQuery.query(user);
    }
}

可以看到这期间用户在使用的过程中,没有写一句SQL,但可以正常操作数据库了。剩下的细节就等着我们去完善。

总结

本文中,我大概总结了一下,Java操作Mysql的演化过程,从最基本的JDBC到自动化的ORM操作,可以看到操作是越来越简单,也越来越灵活了,但底层大致的原理我们还是应该了解的。

本文我参考了韩顺平老师的Mysql基础文章和小四的技术之旅文章。十分感谢!!!原作者的文章中的内容更加详细,具体可在网上查询。


目录
相关文章
|
6月前
|
NoSQL Java 关系型数据库
大厂贬值裁员,我却凭借Java开发进阶面试秘籍(核心版)逆流而上
最近参加了面试或者身边有朋友在面试的兄弟有没有发现,现在的面试不仅会问八股文,还会考察框架、项目实战、算法数据结构等等,需要准备的越来越多。
75 0
|
3月前
|
开发者 CDN 监控
【破局·提速】当Vaadin遇上性能怪圈:开发者的智慧较量与极速加载的实战秘籍!
【8月更文挑战第31天】本文详细介绍了优化Vaadin应用性能的方法,特别是提高加载速度的实战技巧。首先分析性能瓶颈,如服务器响应时间和数据库查询效率等;然后通过代码优化、数据分页与急切加载技术减少资源消耗;接着利用资源压缩合并及CDN加速,进一步提升加载速度;最后通过持续性能监控和测试确保优化效果。通过综合应用这些策略,可显著改善用户体验。
76 0
|
SpringCloudAlibaba Java 开发者
现在国内最牛逼的 Spring CloudAlibaba全栈操作手册,不接受反驳
Spring Cloud Alibaba 近几年在受到国内不少开发者的广泛关注,也成为面试比较吃香的一个技能点了,如果你连Spring Cloud Alibaba 微服务生态都没用过,那么你可能就要被时代淘汰了。
97 0
|
SQL 安全 Java
一路走到ORM框架都经历了什么(上)
一路走到ORM框架都经历了什么
195 0
MyBatis这样用,同事直呼哇塞,堪称最佳实践
MyBatis是一款非常流行的ORM框架,相信很多小伙伴都在使用。我们经常会把它和MyBatis-Plus或者MBG一起使用,用多了之后对于其一些常规操作就不太熟悉了。最近总结了下MyBatis的实用用法和技巧,希望对大家有所帮助!
|
SQL 前端开发 druid
【2021软件创新实验室暑假集训】JDBC(原理、使用以及实现简单的数据库连接池)
【2021软件创新实验室暑假集训】JDBC(原理、使用以及实现简单的数据库连接池)
【2021软件创新实验室暑假集训】JDBC(原理、使用以及实现简单的数据库连接池)
|
运维 监控 前端开发
程序员告别 996 第一步:1 人搞定一个项目,摆脱“重复造轮子”
程序员告别 996 第一步:1 人搞定一个项目,摆脱“重复造轮子”
245 0
程序员告别 996 第一步:1 人搞定一个项目,摆脱“重复造轮子”
|
SQL druid Oracle
在项目中使用c3p0作为数据库连接池,被技术总监怼了
数据库连接是一项非常关键的、有限的、昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。
在项目中使用c3p0作为数据库连接池,被技术总监怼了
|
机器学习/深度学习 算法 网络协议
二本机械转型Java开发,第一次面试就进了阿里。。
二本机械转型Java开发,第一次面试就进了阿里。。
二本机械转型Java开发,第一次面试就进了阿里。。
|
Oracle NoSQL 关系型数据库
十年前,他如何自学技术进阿里?
阿里云高级DBA专家玄惭,讲述十年前通过校招加入阿里的经历和心得,希望对大家有所帮助
十年前,他如何自学技术进阿里?