开始准备生成 sql
在上一篇里, 我们已经取到了我们在生成 sql 语句中所需要的信息, 这一篇里我们开始根据 class 来生成我们需要的 sql. 在这之前我们先确认几件事情
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 就好了.
我们只生成单表的增删改查, 不涉及复杂 sql.
不贴出完整的代码, 以说明思路为主.
毕竟这个是已经写好的代码, 地址在: https://github.com/hjx601496320/JdbcPlus . 所有代码可以在这里找到.
分析 sql
我们主要解决的是增删该查的问题, 所以我们先写如何生成一个新增的 sql.
我么先观察一下 sql 一般来说都有什么构成. 现在先放一个例子出来:
- insert
- INSERT INTO user (name, id, create_date, age, mark, status)
- VALUES (?, ?, ?, ?, ?, ?);
- delete
- DELETE
- FROM user
- WHERE id = ?
- update
- UPDATE user
- SET name = ?,
- id = ?,
- create_date = ?,
- age = ?,
- status = ?
- WHERE id = ?
- select
- SELECT name, id, create_date, age, mark, status
- FROM user
- WHERE id = ?
通过观察上面的 sql, 可以发现其中有一些共性:
都有表的名称.
基本上都包含表中的字段名称.
还有参数.
以上都是废话 ;-)
接下来, 就可以按照每种类型的 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 还是比较好实现的, 我们需要的大致就是:
构建一个对象 User.
调用新增的方法, 将 User 作为参数传入方法.
通过上一篇的解析结果, 拿到所有的字段名称, 与要保存的值. 生成 sql.
通过 JdbcTemplate 执行 sql, 插入数据库.
实现
首先我们要根据 User.java 拿到所有的表的字段个名称, 和对应的值. 就是上一篇写到的: EntityTableRowMapper
拿到字段和 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 中的字段对应的值.
生成插入的 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(";");
生成的结果:
- //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]
现在可以拿着生成的 sql 和值去执行啦~
jdbcTemplate.update(sql, insertColumnValues.toArray());
结束啦, 剩下的下一篇写~~
来源: https://www.cnblogs.com/hebaibai/p/10304633.html