欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

手把手教你写一个java的orm(四)

程序员文章站 2022-04-28 13:17:58
开始准备生成sql 在上一篇里,我们已经取到了我们在生成sql语句中所需要的信息,这一篇里我们开始根据class来生成我们需要的sql。在这之前我们先确认几件事情 1. sql里的参数我们使用占位符的形式。 这里用的是jdbc中的 PreparedStatement ,sql中的参数使用“ ? ”的 ......

开始准备生成sql

在上一篇里,我们已经取到了我们在生成sql语句中所需要的信息,这一篇里我们开始根据class来生成我们需要的sql。在这之前我们先确认几件事情

  1. sql里的参数我们使用占位符的形式。

    这里用的是jdbc中的preparedstatement,sql中的参数使用“”的形式。

    大致上是这样的:

    connection connection = datasource.getconnection();
    preparedstatement preparedstatement = connection.preparestatement("select * from `user` where `status` = ? ;");
    preparedstatement.setobject(1, 0);
    resultset resultset = preparedstatement.executequery();

    但是这样的话我们每次执行都需要手写这些执行sql的繁琐的代码,我在这里选择使用spring-jdbc中的jdbctemplte。这样我就只需要生成sql,然后使用jdbctemplte里的方法来执行sql就好了。

  2. 我们只生成单表的增删改查,不涉及复杂sql。

  3. 不贴出完整的代码,以说明思路为主。

    毕竟这个是已经写好的代码,地址在:https://github.com/hjx601496320/jdbcplus 。所有代码可以在这里找到。

分析sql

我们主要解决的是增删该查的问题,所以我们先写如何生成一个新增的sql。

我么先观察一下sql一般来说都有什么构成。现在先放一个例子出来:

  1. insert

    insert into user (name, id, create_date, age, mark, status)
    values (?, ?, ?, ?, ?, ?);
  2. delete

    delete
    from user
    where id = ? 
  3. update

    update user
    set name        = ?,
        id          = ?,
        create_date = ?,
        age         = ?,
        status      = ?
    where id = ? 
  4. select

    select name, id, create_date, age, mark, status
    from user
    where id = ?

通过观察上面的sql,可以发现其中有一些共性:

  1. 都有表的名称。
  2. 基本上都包含表中的字段名称。
  3. 还有参数。
  4. 以上都是废话 ;-)

接下来,就可以按照每种类型的sql来创建sql了。

操作对象

一下所有的对象都是这个user.java

import javax.persistence.column;
import javax.persistence.id;
import javax.persistence.table;
import java.util.date;


@table(name = "user")
public class user {

    @column(name = "name")
    private string name;

    @id
    @column(name = "id")
    private int id;

    @column(name = "age")
    private int age;

    @column(name = "mark")
    private string mark;

    @column(name = "create_date")
    private date createdate;

    @column(name = "status")
    private int status;

//   getter setter tostring
}

先写点工具代码

主要用来操作字符串

import java.util.collection;
import java.util.iterator;

/**
 * @author hjx
 */
public class stringutils {

    public static final string space = " ";

    public static final string blank = "";

    public static final string comma = ", ";


    /**
     * 重复字符串
     *
     * @param str
     * @param number
     * @return
     */
    public static string[] repeat(string str, int number) {
        assert.notnull(str);
        string[] strings = new string[number];
        for (int i = 0; i < number; i++) {
            strings[i] = str;
        }
        return strings;
    }

    /**
     * 组合字符串
     *
     * @param strings
     * @return
     */
    public static string append(final object... strings) {
        stringbuilder builder = new stringbuilder();
        for (object s1 : strings) {
            if (s1 == null) {
                continue;
            }
            builder.append(s1.tostring());
        }
        return builder.tostring();
    }

    /**
     * 组合字符串
     *
     * @param collection
     * @param separator
     * @return
     */
    public static string join(collection collection, string separator) {
        stringbuffer var2 = new stringbuffer();
        for (iterator var3 = collection.iterator(); var3.hasnext(); var2.append((string) var3.next())) {
            if (var2.length() != 0) {
                var2.append(separator);
            }
        }
        return var2.tostring();
    }
}

用来从对象中取值的,使用反射。

/**
 * 取值
 *
 * @param target 要从哪一个对象中取值
 * @param field  要取这个对象的那个属性的值
 * @return
 */
public static object getvalue(object target, field field) {
    //忽略掉private
    field.setaccessible(true);
    try {
        return field.get(target);
    } catch (illegalaccessexception e) {
        e.printstacktrace();
    }
    return null;
}

​ 用来给对象设置值的,还是反射。

/**
 * 设置值
 *
 * @param target 要从哪一个对象中取值
 * @param field  要取这个对象的那个属性的值
 * @param value  要设置的值
 * @return
 */
public static boolean setvalue(object target, field field, object value) {
    field.setaccessible(true);
    try {
        field.set(target, value);
        return true;
    } catch (illegalaccessexception e) {
        e.printstacktrace();
    }
    return false;
}

下面就可以开始创建各种sql了~~~

生成sql:insert

思路

新增的sql还是比较好实现的,我们需要的大致就是:

  1. 构建一个对象 user。
  2. 调用新增的方法,将user作为参数传入方法。
  3. 通过上一篇的解析结果,拿到所有的字段名称,与要保存的值。生成sql。
  4. 通过jdbctemplate执行sql,插入数据库。

实现

首先我们要根据user.java拿到所有的表的字段个名称,和对应的值。就是上一篇写到的:entitytablerowmapper

  1. 拿到字段和class属性的值

    map<string, field> columnfieldmapper = entitytablerowmapper.getcolumnfieldmapper();
    insertcolumns = new arraylist(columnfieldmapper.size());
    for (map.entry<string, field> stringfieldentry : columnfieldmapper.entryset()) {
        field field = stringfieldentry.getvalue();
        object value = entityutils.getvalue(entity, field);
        if (value == null) {
            continue;
        }
        insertcolumns.add(stringfieldentry.getkey());
        insertcolumnvalues.add(value);
    }

    这里有两个变量:

    insertcolumns:sql中的字段名。

    insertcolumnvalues:sql中的字段对应的值。

  2. 生成插入的sql:

    stringbuilder builder = new stringbuilder();
    int size = insertcolumns.size();
    builder.append("insert into ").append(gettablename()).append(stringutils.space);
    builder.append(stringutils.append("( ", stringutils.join(insertcolumns, ", "), " ) "));
    builder.append("values ");
    for (int i = 0; i < insertcount; i++) {
        builder.append("( ");
        string[] repeat = stringutils.repeat("?", size);
        builder.append(stringutils.join(arrays.aslist(repeat), ", "));
        builder.append(" )");
        if (i != insertcount - 1) {
            builder.append(stringutils.comma);
        }
    }
    builder.append(";");
  3. 生成的结果:

    //user
    user user = new user();
    user.setid(10);
    user.setcreatedate(new date());
    user.setage(20);
    user.setmark("ceshi");
    user.setname("heiheihei");
    //sql
    insert into user ( name, id, create_date, age, mark, status ) values ( ?, ?, ?, ?, ?, ? );
    //value
    [heiheihei, 10, tue jan 22 16:33:00 cst 2019, 20, ceshi, 0]
  4. 现在可以拿着生成的sql和值去执行啦~

    jdbctemplate.update(sql, insertcolumnvalues.toarray());
结束啦,剩下的下一篇写~~