jdbc是ORM框架的基础,但将数据库中的表映射到java对象,并进行增删改查,并不是一件简单的事情。

涉及到jdbc、注解和反射的一些基础知识。

以下内容来自网友的分享,并做了一些增减,作为笔记记录与此。

一、首先是数据表

假如数据库中有一张表app_base_log,在java中建立它对应的类。

@Table(name = "app_base_log")
public class AppBaseLog implements Serializable {
private static final long serialVersionUID = -5206763271093824440L;
@Column(name = "dvid")
private String dvid;
@Column(name = "type")
private String type; public AppBaseLog() {
} public AppBaseLog(String dvid, String type) {
this.dvid = dvid;
this.type = type;
} public String getDvid() {
return dvid;
} public void setDvid(String dvid) {
this.dvid = dvid;
} public String getType() {
return type;
} public void setType(String type) {
this.type = type;
}
}

这里的注解都是自定义的,并非来自hibernate和mybatis。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Table {
String name();
} /**
* Created by wangbin10 on 2018/8/13.
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Id {
String name();
String type() default "int";
int length() default 20;
int increment() default 1;
} /**
* Created by wangbin10 on 2018/8/13.
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column {
String name();
String type() default "string";
int length() default 20;
}

二、核心代码

/**
* Created by wangbin10 on 2018/8/13.
*/
public class SimpleORM<E> {
@Autowired
private QueryRunner queryRunner;
/**
* 添加一个对象
*/
public int add(E element) throws SQLException {
Class clazz = element.getClass();
String tableName = getTableName(clazz);
Field[] fields = clazz.getDeclaredFields();
String sql = getInsertSql(tableName, fields.length);
//通过对象和属性列表获取对应属性的值
Object[] params = getSqlParams(element, fields);
int result = -1;
result = queryRunner.update(sql, params);
return result;
} /**
* 根据对象获取sql语句的参数
*/
private Object[] getSqlParams(E element, Field[] fields) {
Object[] params = new Object[fields.length];
for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);
try {
params[i] = fields[i].get(element);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return params;
} /**
* 获取插入对象的sql语句
*/
private String getInsertSql(String tableName, int length) {
StringBuilder sql = new StringBuilder();
sql.append("insert into ").append(tableName).append(" values(");
for (int i = 0; i < length; i++) {
sql.append("?,");
}
sql.deleteCharAt(sql.length() - 1);
sql.append(")");
return sql.toString();
} /**
* 根据值对象的注解获取其对应的表名称
*/
private String getTableName(Class<E> clazz) {
boolean existTableAnno = clazz.isAnnotationPresent(Table.class);
if (!existTableAnno) {
throw new RuntimeException(clazz + " 没有Table注解.");
}
Table tableAnno = clazz.getAnnotation(Table.class);
return tableAnno.name();
} /**
* 更新一个对象
*/
public int update(E element) throws SQLException {
Class clazz = element.getClass();
Field[] fields = clazz.getDeclaredFields();
Object[] params = new Object[fields.length];
String sql = getUpdateSql(element, params);
int result = queryRunner.update(sql, params);
return result;
} /**
* 获取更新记录的sql语句并更新参数
*/
private String getUpdateSql(E element, Object[] params) {
Class clazz = element.getClass();
String tableName = getTableName(clazz);
Field[] fields = clazz.getDeclaredFields();
StringBuilder updateSql = new StringBuilder();
updateSql.append("update ").append(tableName).append(" set ");
String idName = "";
int index = 0; // 记录参数的位置
for (int i = 0; i < fields.length; i ++){
fields[i].setAccessible(true);
// 找到id对应的列名和值
if (fields[i].isAnnotationPresent(Id.class)){
idName = fields[0].getAnnotation(Id.class).name();
try {
params[params.length-1] = fields[i].get(element); // id作为update sql 的最后一个参数
if (params[params.length-1] == null)
throw new RuntimeException(element + "没有Id属性!");
} catch (IllegalAccessException e) {
System.out.println(e.getMessage());
System.out.println("获取" + element + "的属性值失败!");
}
}
boolean isPresent = fields[i].isAnnotationPresent(Column.class);
if (isPresent) {
Column column = fields[i].getAnnotation(Column.class);
String columnName = column.name();
updateSql.append(" ").append(columnName).append( " = ? ,");
try {
params[index++] = fields[i].get(element); // 添加参数到数组,并更新下标
} catch (IllegalAccessException e) {
System.out.println(e.getMessage());
System.out.println("获取" + element + "的属性值失败!");
}
}
}
updateSql.deleteCharAt(updateSql.length()-1);
updateSql.append("where ").append(idName).append(" = ?");
return updateSql.toString();
} /**
* 根据id删除一个对象
*/
public int delete(String id, Class<E> clazz) throws SQLException {
String deleteSql = getDeleteSql(clazz);
int result = queryRunner.update(deleteSql, id);
return result;
} private String getDeleteSql(Class<E> clazz) {
String tableName = getTableName(clazz);
String idName = getIdName(clazz);
StringBuilder deleteSql = new StringBuilder();
deleteSql.append("delete from ").append(tableName).append(" where ").append(idName).append(" = ?");
return deleteSql.toString();
} /**
* 获取id属性对应的列名,根据值对象的字节码
*/
private String getIdName(Class<E> clazz) {
Field[] fields = clazz.getDeclaredFields();
String idName = null;
for (Field field : fields) {
field.setAccessible(true);
if (field.isAnnotationPresent(Id.class)) {
idName = field.getAnnotation(Id.class).name();
}
}
if (idName == null) {
throw new RuntimeException(clazz + "没有指定@Id注解!");
}
return idName;
} /**
* 根据id查找一个对象
*/
public E query(String id, Class<E> clazz) throws SQLException {
String selectSql = getSelectSql(clazz);
E result = queryRunner.query(selectSql, new BeanHandler<E>(clazz), id);
return result;
} private String getSelectSql(Class<E> clazz) {
String tableName = getTableName(clazz);
String idName = getIdName(clazz);
StringBuilder selectSql = new StringBuilder();
selectSql.append("select * from ").append(tableName).append(" where ").append(idName).append(" = ?");
return selectSql.toString();
} public List<E> queryToList(String sql, Class<E> clazz) throws SQLException {
List<E> result = queryRunner.query(sql, new BeanListHandler<E>(clazz));
return result;
} public Object[] queryToArray(String sql) throws SQLException {
Object[] result = queryRunner.query(sql, new ArrayHandler());
return result;
} /**
* 查找该类对应的表中记录的数目(对应记录的数目)
*/
public int count(Class<E> clazz) throws SQLException {
String tableName = getTableName(clazz);
String sql = "select count(*) from " + tableName;
long result = (Long) queryRunner.query(sql, new ScalarHandler());
return (int) result;
}
}

java之jdbc学习——QueryRunner的更多相关文章

  1. java之JDBC学习总结

    以前一直以为jdbc是很高大上的东西,没想到今天学了jdbc,惊喜来了,just a tool!当然工具是用来帮助人们学习和提供方便的,所以总结了一下,也就是简单的三板斧: first :加载驱动 t ...

  2. Java之JDBC学习

    (一),MySql数据库 1,MySql数据库的数据类型定义 2,完整性约束: 3,索引: 作用:唯一作用就是加快对表查询速度,索引通过快速路径方法访问来快速定位数据,从而减少磁盘的II/O; 缺点: ...

  3. Java JDBC学习实战(二): 管理结果集

    在我的上一篇博客<Java JDBC学习实战(一): JDBC的基本操作>中,简要介绍了jdbc开发的基本流程,并详细介绍了Statement和PreparedStatement的使用:利 ...

  4. Java数据库连接--JDBC调用存储过程,事务管理和高级应用

    相关链接:Jdbc调用存储过程 一.JDBC常用的API深入详解及存储过程的调用 1.存储过程的介绍 我们常用的操作数据库语言SQL语句在执行的时候要先进行编译,然后执行,而存储过程是在大型数据库系统 ...

  5. 一位资深程序员大牛给予Java初学者的学习路线建议

    java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是我你是如何学习Java的,能不能给点建议?今天我是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈 ...

  6. 回答阿里社招面试如何准备,顺便谈谈对于Java程序猿学习当中各个阶段的建议

    引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...

  7. Java程序员学习之路

    1. Java语言基础 谈到Java语 言基础学习的书籍,大家肯定会推荐Bruce Eckel的<Thinking in Java>.它是一本写的相当深刻的技术书籍,Java语言基础部分基 ...

  8. 20145304 Java第九周学习报告

    20145304<Java程序设计>第九周学习总结 教材学习内容总结 JDBC简介 JDBC全名Java DataBase Connectivity,是Java联机数据库的标准规范.定义了 ...

  9. 如何准备阿里社招面试,顺谈 Java 程序员学习中各阶段的建议

    引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...

随机推荐

  1. delphi 10.2 创建并使用资源文件(一共22种格式,RCDATA是自定义格式)

    windows支持以下资源格式: 1 2 //下面是 Windows 支持的资源格式: RT_CURSOR = MakeIntResource(1); RT_BITMAP = MakeIntResou ...

  2. LaTeX —— 特殊符号与数学字体

    1. 特殊符号 ℓ(\ell):用于和大小的 I 和 数字 1 相区分 R(\Re) ∇(\nabla):微分算子 2. 数学字体 mathbb:blackboard bold,黑板粗体 mathca ...

  3. OpenCV图像的基础叠加

    程序及分析 /* * FileName : blend.cpp * Author : xiahouzuoxin @163.com * Version : v1.0 * Date : Mon 28 Ju ...

  4. 网络故障模拟,cpu高压以及docker中的实现

    利用tc进行丢包 通过网络丢包来模拟网络故障,是测试中一个重要的测试项目.这对服务来说可以测试其在网络故障时的异常处理的能力,对于服务的可靠性是一个相当严苛的测试. 网卡名为$netcard,丢包率为 ...

  5. JS 实现Map

    function Map() { this.arr = new Array(); var struct = function(key, value) { this.key = key; this.va ...

  6. AABB边框、OBB边框、通过比较球包围

    1) AABB 包围盒: AABB 包围盒是与坐标轴对齐的包围盒, 简单性好, 紧密性较差(尤其对斜对角方向放置的瘦长形对象, 採用AABB, 将留下非常大的边角空隙, 导致大量不是必需的包围盒相交測 ...

  7. 让你的Blend“编辑其他模板”菜单里出现你的Style

    原文:让你的Blend"编辑其他模板"菜单里出现你的Style 如图.. 昨天在做控件的时候遇到了一个新的要求,让美工可以在Blend里直接编辑自定义控件里子内容的模板.于是乎疯狂 ...

  8. WPF里的一些Effect特效

    原文:WPF里的一些Effect特效 Blend的特效都在Microsoft.Expression.Media.Effects里,用之前添加一下引用. 可以在前台选中对象后直接点击Effect新建一种 ...

  9. dedecms织梦出现“Upload filetype not allow”原因和解决方案

    资源:武汉科技有限公司倍频猫 我最近升级DEDE5.6出现此问题后.和解决的方法. 假设有同学是按某些朋友用删除代码的方法解决这个问题的话,建议你修正此做法,毕竟这是有非常大安全风险的.而DEDE本身 ...

  10. Fidder模拟发送请求

    在Fiddler的Composer一栏,可以模拟请求 举例 首先通过浏览器访问页面http://baidu.com/ ,在右侧可以拿到请求情况 在Inspectors一栏可以看到请求和响应结果,复制请 ...