万能 CURD 接口

在实际的使用时,经常遇到这么一个问题,我要从某种数据库中查询出数据,但是不告诉你字段/属性。
乍一看,这个怎么可能,不告诉我字段/属性,要把数据查出来,后来在github上看见一段代码,读了这段代码后恍然大悟。还是 too young to simple

原理是通过JDBC的getMetaData()方法来获取表结构,里面用到了反射 (进行了处理,高并发下还是不建议使用)
比较重要的一点是查询的时候数据库有数据字典,可以根据数据字典获取所有字段/属性

实测,MySQL 可用
代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
* 通用接口<br>
*
* @author weikeqin.cn@gmail.com
* @version V1.0
* @date 2017-07-11 15:12
*/
public interface Executor {

/**
* 查询接口
*
* @param sql 查询语句
* @param params 占位符对应的参数
* @param conn 连接
* @return Iterator<LinkedHashMap<String, Object>>
* @throws SQLException
*/
Iterator<Map<String, Object>> query(String sql, Map<Integer, Object> params, Connection conn) throws SQLException;

/**
* (单条)增删改接口
*
* @param sql 增删改语句
* @param params 占位符对应的参数
* @param conn 连接
* @return 操作的条数
* @throws SQLException
*/
int operat(String sql, Map<Integer, Object> params, Connection conn) throws SQLException;

/**
* 批量操作<br>
* 大于等于0是成功处理的
*
* @param sql 增删改语句
* @param list 占位符对应的参数
* @param conn 连接
* @return
* @throws SQLException
* @author : weikeqin.cn@gmail.com
* @date : 2017-09-08 14:47:15
*/
int[] betchOperat(String sql, List<Map<Integer, Object>> list, Connection conn) throws SQLException;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import java.sql.*;
import java.util.*;

/**
* @author weikeqin.cn@gmail.com
* @version V1.0
* @date 2017-07-11 15:31
*/
public class ExecutorImpl implements Executor {

/**
* @param sql 查询语句
* @param params 占位符 参数
* @param conn 连接
* @return
*/
@Override
public Iterator<Map<String, Object>> query(String sql, Map<Integer, Object> params,
Connection conn) throws SQLException {

final PreparedStatement statement = conn.prepareStatement(sql);
// 设置参数
setParameters(statement, params);
// 执行查询并获得结果
final ResultSet result = statement.executeQuery();
// 封装返回
return new Iterator<Map<String, Object>>() {

boolean hasNext = result.next();
// 所有字段
public List<String> columns;
// 字段个数
public int columnsCount;

/**
*
*
* @return
*/
@Override
public boolean hasNext() {
return hasNext;
}

/**
* 获得所有字段<br>
* 第一次会查询出所有字段,第二 第三次 直接用columns
*
* @return
* @throws SQLException
*/
private List<String> getColumns() throws SQLException {
if (columns != null) {
return columns;
}

ResultSetMetaData metaData = result.getMetaData();
// 查询出的字段
int count = metaData.getColumnCount();
List<String> cols = new ArrayList<>(count);
for (int i = 1; i <= count; i++) {
cols.add(metaData.getColumnName(i));
}

columnsCount = cols.size();
return columns = cols;
}

/**
*
* @return
*/
@Override
public Map<String, Object> next() {
try {
if (hasNext) {
//
Map<String, Object> map = new LinkedHashMap<>(columnsCount);
for (String col : getColumns()) {
map.put(col, result.getObject(col));
}
hasNext = result.next();
if (!hasNext) {
result.close();
statement.close();
}
return map;
} else {
throw new NoSuchElementException();
}

} catch (SQLException e) {
throw new RuntimeException(e);
}
}

/**
*
*/
@Override
public void remove() {
}
};

}

/**
* 增删改操作
*
* @param sql 增删改语句
* @param params 占位符参数
* @param conn 连接
* @return
* @throws SQLException
*/
@Override
public int operat(String sql, Map<Integer, Object> params, Connection conn) throws SQLException {
PreparedStatement statement = conn.prepareStatement(sql);
setParameters(statement, params);
int count = statement.executeUpdate();
statement.close();
return count;
}

/**
* 大于等于0是成功处理的
*
* @param sql
* @param list
* @param conn
* @author : weikeqin.cn@gmail.com
* @date : 2017-09-08 14:48:50
*/
@Override
public int[] betchOperat(String sql, List<Map<Integer, Object>> list, Connection conn)
throws SQLException {

conn.setAutoCommit(false);
PreparedStatement statement = conn.prepareStatement(sql);

int size = list.size();
for (int i = 0; i < size; i++) {
// 一条语句里的多个占位符参数
Map<Integer, Object> map = list.get(i);
setParameters(statement, map);
statement.addBatch();
}

int[] array = statement.executeBatch();
conn.commit();
statement.close();
return array;
}

/**
* 赋值 给占位符赋值
*
* @param statement
* @param params
* @throws SQLException
* @author weikeqin.cn@gmail.com
*/
private void setParameters(PreparedStatement statement, Map<Integer, Object> params)
throws SQLException {

// 校验
if (params == null || params.isEmpty()) {
return;
}

for (Map.Entry<Integer, Object> entry : params.entrySet()) {
statement.setObject(entry.getKey(), entry.getValue());
}
} // end method

}