一路走到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基础文章和小四的技术之旅文章。十分感谢!!!原作者的文章中的内容更加详细,具体可在网上查询。


目录
相关文章
|
11月前
|
消息中间件 缓存 安全
讲理论,重实战!阿里独家SpringBoot王者晋级之路小册,太强了!
大家平时学习SpringBoot的方式也一般是看大量博客或者是找一些业界评价好点的书籍,虽然SpringBoot相关资料很多,但是大多不成体系,很少有真正有能从0到1,详解Spring Boot一切从代码案例出发的案头笔记。 今天给小伙伴分享的就是来自阿里的SpringBoot王者晋级之路小册,这份小册从SpringBoot的开发环境部署开始,把Spring Boot搭建Web项目、操作数据库、使用缓存、日志、整合安全框架、结合消息队列和搜索框架,以及在实际应用中的部署全部讲得清清楚楚。
|
SQL 安全 Java
一路走到ORM框架都经历了什么(上)
一路走到ORM框架都经历了什么
152 0
|
JSON 前端开发 Java
JavaWeb编年史(远古时期)
JavaWeb编年史(远古时期)
192 0
MyBatis这样用,同事直呼哇塞,堪称最佳实践
MyBatis是一款非常流行的ORM框架,相信很多小伙伴都在使用。我们经常会把它和MyBatis-Plus或者MBG一起使用,用多了之后对于其一些常规操作就不太熟悉了。最近总结了下MyBatis的实用用法和技巧,希望对大家有所帮助!
|
监控 前端开发 jenkins
新来个技术总监,给团队引入了这款开发神器,同事直呼哇塞
带团队时间久了,就能发现整个 Team 都渐渐疲了。前两年老板还专门买了个系统搞 OKR,现在也不大提了;Scrum 我们也搞了,用起来也就那样;项目管理工具试了好几个,禅道、Worktile、现在用 Coding,反正有一个能用的就行;微服务化改造从去年开始在吭哧吭哧搞,我们自己搞得觉得很厉害,但业务部门那边就觉得没啥差别,搞不懂你们研发部门每天在弄些什么,赶紧做我们提的需求要紧。
新来个技术总监,给团队引入了这款开发神器,同事直呼哇塞
|
前端开发 Android开发
我奇怪的安卓开发历程(内含本人不太成熟的技术观)(四)
工作一天下来,最大的收获便是我发现项目写了半年我还是不知道这是个啥架构的,通过几次和同事沟通交流,以及浏览许多介绍和实例MVP、MVVM架构的文章,还是不了了之,当然,不能否认的是同事认为这是MVP架构的项目,我也挺倾向这个观点。
|
程序员 开发工具 Android开发
我奇怪的安卓开发历程(内含本人不太成熟的技术观)(三)
半年的开发工作通过统计git的提交记录发现其实我提交行数最多的项目也就1228行:
|
存储 Android开发
我奇怪的安卓开发历程(内含本人不太成熟的技术观)(二)
初出茅庐的我在开发工作中成长,收获了许多,但其实也引出了一堆问题。
|
SQL druid Oracle
在项目中使用c3p0作为数据库连接池,被技术总监怼了
数据库连接是一项非常关键的、有限的、昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。
在项目中使用c3p0作为数据库连接池,被技术总监怼了
|
机器学习/深度学习 算法 网络协议
二本机械转型Java开发,第一次面试就进了阿里。。
二本机械转型Java开发,第一次面试就进了阿里。。
二本机械转型Java开发,第一次面试就进了阿里。。