`

反射+注释,根据实体类对象生成SQL语句工具类(转)

    博客分类:
  • java
 
阅读更多

最近在写一个公司内部项目,由于觉得配置Hibernate过于繁琐,索性使用了spring的jdbc,可是又要写很多的sql语句,为了偷偷懒,于是就写个能通过实体类对象生成SQL语句的工具类。

 

目前只在MySql数据库上实验通过,其他数据库未测试。

 

本工具类还有很多不足之处,不过好在可以满足自己一些简单的日常使用。

 

上代码了。

 

字段类型:

package net.tjnwdseip.util;

public enum FieldType {

	STRING,NUMBER,DATE
}

 

字段注释:

package net.tjnwdseip.util;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldAnnotation {

	String fieldName();
	
	FieldType fieldType();
	
	boolean pk();
}

 

表名注释:

package net.tjnwdseip.util;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TableAnnotation {

	String tableName();
}

 

SQL语句生成工具类:

package net.tjnwdseip.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

/**
 * 
 * @ClassName: CreateSqlTools
 * @Description: TODO(根据实体类对象生成SQL语句)
 * @author LiYang
 * @date 2012-5-4 下午10:07:03
 * 
 */
public class CreateSqlTools {

	/**
	 * 
	 * @Title: getTableName
	 * @Description: TODO(获取表名)
	 * @param @param obj
	 * @param @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	private static String getTableName(Object obj) {
		String tableName = null;
		if (obj.getClass().isAnnotationPresent(TableAnnotation.class)) {
			tableName = obj.getClass().getAnnotation(TableAnnotation.class)
					.tableName();
		}
		return tableName;
	}

	/**
	 * 
	 * @Title: getAnnoFieldList
	 * @Description: TODO(获取所有有注释的字段,支持多重继承)
	 * @param @param obj
	 * @param @return 设定文件
	 * @return List<Field> 返回类型
	 * @throws
	 */
	@SuppressWarnings("rawtypes")
	private static List<Field> getAnnoFieldList(Object obj) {
		List<Field> list = new ArrayList<Field>();
		Class superClass = obj.getClass().getSuperclass();
		while (true) {
			if (superClass != null) {
				Field[] superFields = superClass.getDeclaredFields();
				if (superFields != null && superFields.length > 0) {
					for (Field field : superFields) {
						if (field.isAnnotationPresent(FieldAnnotation.class)) {
							list.add(field);
						}
					}
				}
				superClass = superClass.getSuperclass();
			} else {
				break;
			}
		}
		Field[] objFields = obj.getClass().getDeclaredFields();
		if (objFields != null && objFields.length > 0) {
			for (Field field : objFields) {
				if (field.isAnnotationPresent(FieldAnnotation.class)) {
					list.add(field);
				}
			}
		}
		return list;
	}

	/**
	 * 
	 * @Title: getFieldValue
	 * @Description: TODO(获取字段的值,支持多重继承)
	 * @param @param obj
	 * @param @param field
	 * @param @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	@SuppressWarnings({ "rawtypes" })
	private static String getFieldValue(Object obj, Field field) {
		String value = null;
		String name = field.getName();
		String methodName = "get" + name.substring(0, 1).toUpperCase()
				+ name.substring(1);
		Method method = null;
		Object methodValue = null;
		try {
			method = obj.getClass().getMethod(methodName);
		} catch (NoSuchMethodException | SecurityException e1) {
			// TODO Auto-generated catch block
		}
		if (method != null) {
			try {
				methodValue = method.invoke(obj);
			} catch (IllegalAccessException | IllegalArgumentException
					| InvocationTargetException e) {
				// TODO Auto-generated catch block
			}
			if (methodValue != null) {
				value = methodValue.toString();
			} else {
				Class objSuperClass = obj.getClass().getSuperclass();
				while (true) {
					if (objSuperClass != null) {
						try {
							methodValue = method.invoke(objSuperClass);
						} catch (IllegalAccessException
								| IllegalArgumentException
								| InvocationTargetException e) {
							// TODO Auto-generated catch block
						}
						if (methodValue != null) {
							value = methodValue.toString();
							break;
						} else {
							objSuperClass = objSuperClass.getSuperclass();
						}
					} else {
						break;
					}
				}
			}
		}
		return value;
	}

	/**
	 * 
	 * @Title: getInsertSql
	 * @Description: TODO(根据实体类对象字段的值生成INSERT SQL语句,可选固定参数)
	 * @param @param obj
	 * @param @param fixedParams
	 *        固定参数(如该参数与实体类中有相同的字段,则忽略实体类中的对应字段,HashMap<String
	 *        ,String>,key=指定字段名,value=对应字段的值)
	 * @param @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	public static String getInsertSql(Object obj,
			HashMap<String, String> fixedParams) {
		String insertSql = null;
		String tableName = getTableName(obj);
		if (tableName != null) {
			StringBuffer sqlStr = new StringBuffer("INSERT INTO ");
			StringBuffer valueStr = new StringBuffer(" VALUES (");
			List<Field> annoFieldList = getAnnoFieldList(obj);
			if (annoFieldList != null && annoFieldList.size() > 0) {
				sqlStr.append(tableName + " (");
				if (fixedParams != null && fixedParams.size() > 0) {
					Iterator<String> keyNames = fixedParams.keySet().iterator();
					while (keyNames.hasNext()) {
						String keyName = (String) keyNames.next();
						sqlStr.append(keyName + ",");
						valueStr.append(fixedParams.get(keyName) + ",");
					}
				}
				for (Field field : annoFieldList) {
					FieldAnnotation anno = field
							.getAnnotation(FieldAnnotation.class);
					if (!anno.pk()) {
						Object fieldValue = getFieldValue(obj, field);
						if (fieldValue != null) {
							if (fixedParams != null && fixedParams.size() > 0) {
								Iterator<String> keyNames = fixedParams
										.keySet().iterator();
								boolean nextFieldFlag = false;
								while (keyNames.hasNext()) {
									String keyName = (String) keyNames.next();
									if (anno.fieldName().equals(keyName)) {
										nextFieldFlag = true;
										break;
									}
								}
								if (nextFieldFlag) {
									break;
								}
							}
							sqlStr.append(anno.fieldName() + ",");
							switch (anno.fieldType()) {
							case NUMBER:
								valueStr.append(fieldValue + ",");
								break;
							default:
								valueStr.append("'" + fieldValue + "',");
								break;
							}
						}
					}
				}
				insertSql = sqlStr.toString().substring(0, sqlStr.length() - 1)
						+ ")"
						+ valueStr.toString().substring(0,
								valueStr.length() - 1) + ")";
			}
		}
		return insertSql;
	}

	/**
	 * 
	 * @Title: getInsertSql
	 * @Description: TODO(根据实体类对象字段的值生成INSERT SQL语句)
	 * @param @param obj
	 * @param @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	public static String getInsertSql(Object obj) {
		return getInsertSql(obj, null);
	}

	/**
	 * 
	 * @Title: getUpdateSql
	 * @Description: TODO(根据实体类对象字段的值生成UPDATE SQL语句,可选更新条件为主键,可选固定更新参数)
	 * @param @param obj
	 * @param @param reqPk 是否指定更新条件为主键(true=是,false=否)
	 * @param @param fixedParams
	 *        固定参数(如该参数与实体类中有相同的字段,则忽略实体类中的对应字段,HashMap<String
	 *        ,String>,key=指定字段名,value=对应字段的值)
	 * @param @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	public static String getUpdateSql(Object obj, boolean reqPk,
			HashMap<String, String> fixedParams) {
		String updateSql = null;
		String tableName = getTableName(obj);
		if (tableName != null) {
			List<Field> annoFieldList = getAnnoFieldList(obj);
			if (annoFieldList != null && annoFieldList.size() > 0) {
				StringBuffer sqlStr = new StringBuffer("UPDATE " + tableName);
				StringBuffer valueStr = new StringBuffer(" SET ");
				String whereStr = " WHERE ";
				if (fixedParams != null && fixedParams.size() > 0) {
					Iterator<String> keyNames = fixedParams.keySet().iterator();
					while (keyNames.hasNext()) {
						String keyName = (String) keyNames.next();
						valueStr.append(keyName + "="
								+ fixedParams.get(keyName) + ",");
					}
				}
				for (Field field : annoFieldList) {
					String fieldValue = getFieldValue(obj, field);
					if (fieldValue != null) {
						FieldAnnotation anno = field
								.getAnnotation(FieldAnnotation.class);
						if (!anno.pk()) {
							if (fixedParams != null && fixedParams.size() > 0) {
								boolean nextFieldFlag = false;
								Iterator<String> keyNames = fixedParams
										.keySet().iterator();
								while (keyNames.hasNext()) {
									String keyName = (String) keyNames.next();
									if (anno.fieldName().equals(keyName)) {
										nextFieldFlag = true;
										break;
									}
								}
								if (nextFieldFlag) {
									break;
								}
							}
							valueStr.append(anno.fieldName() + "=");
							switch (anno.fieldType()) {
							case NUMBER:
								valueStr.append(fieldValue + ",");
								break;
							default:
								valueStr.append("'" + fieldValue + "',");
								break;
							}
						} else {
							if (reqPk) {
								whereStr += anno.fieldName() + "=" + fieldValue;
							}
						}
					}
				}
				updateSql = sqlStr.toString()
						+ valueStr.toString().substring(0,
								valueStr.length() - 1)
						+ (reqPk ? whereStr : "");
			}
		}
		return updateSql;
	}

	/**
	 * 
	 * @Title: getUpdateSql
	 * @Description: TODO(根据实体类对象字段的值生成UPDATE SQL语句,无条件)
	 * @param @param obj
	 * @param @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	public static String getUpdateSql(Object obj) {
		return getUpdateSql(obj, false, null);
	}

	/**
	 * 
	 * @Title: getUpdateSql
	 * @Description: TODO(根据实体类对象字段的值生成UPDATE SQL语句,可选更新条件为主键)
	 * @param @param obj
	 * @param @param reqPk 是否指定更新条件为主键(true=是,false=否)
	 * @param @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	public static String getUpdateSql(Object obj, boolean reqPk) {
		return getUpdateSql(obj, reqPk, null);
	}

	/**
	 * 
	 * @Title: getDeleteSql
	 * @Description: TODO(根据实体类对象字段的值生成有条件的DELETE
	 *               SQL语句,可选主键为删除条件或使用各个字段的值为条件,多个条件用AND连接)
	 * @param @param obj
	 * @param @param reqPk 是否指定更新条件为主键(true=是,false=否)
	 * @param @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	public static String getDeleteSql(Object obj, boolean reqPk) {
		String deleteSql = null;
		String tableName = getTableName(obj);
		if (tableName != null) {
			StringBuffer delSqlBuffer = new StringBuffer("DELETE FROM ");
			List<Field> annoFieldList = getAnnoFieldList(obj);
			if (annoFieldList != null && annoFieldList.size() > 0) {
				delSqlBuffer.append(tableName + " WHERE ");
				for (Field field : annoFieldList) {
					if (reqPk) {
						FieldAnnotation anno = field
								.getAnnotation(FieldAnnotation.class);
						if (anno.pk()) {
							String fieldValue = getFieldValue(obj, field);
							delSqlBuffer.append(anno.fieldName() + "=");
							switch (anno.fieldType()) {
							case NUMBER:
								delSqlBuffer.append(fieldValue);
								break;
							default:
								delSqlBuffer.append("'" + fieldValue + "'");
								break;
							}
							break;
						}
					} else {
						String fieldValue = getFieldValue(obj, field);
						if (fieldValue != null) {
							FieldAnnotation anno = field
									.getAnnotation(FieldAnnotation.class);
							delSqlBuffer.append(anno.fieldName() + "=");
							switch (anno.fieldType()) {
							case NUMBER:
								delSqlBuffer.append(fieldValue + " AND ");
								break;
							default:
								delSqlBuffer
										.append("'" + fieldValue + "' AND ");
								break;
							}
						}
					}
				}
				if (reqPk) {
					deleteSql = delSqlBuffer.toString();
				} else {
					deleteSql = delSqlBuffer.toString().substring(0,
							delSqlBuffer.length() - 5);
				}
			}
		}
		return deleteSql;
	}

	/**
	 * 
	 * @Title: getDeleteSql
	 * @Description: TODO(根据实体类对象字段的值生成有条件的DELETE SQL语句,使用各个字段的值为条件,多个条件用AND连接)
	 * @param @param obj
	 * @param @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	public static String getDeleteSql(Object obj) {
		return getDeleteSql(obj, false);
	}

	/**
	 * 
	 * @Title: getSelectAllSql
	 * @Description: TODO(根据实体类对象字段的值生成SELECT SQL语句,无查询条件)
	 * @param @param obj
	 * @param @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	public static String getSelectAllSql(Object obj) {
		String selectSql = null;
		String tableName = getTableName(obj);
		if (tableName != null) {
			StringBuffer selectBuffer = new StringBuffer("SELECT ");
			List<Field> annoFieldList = getAnnoFieldList(obj);
			if (annoFieldList != null && annoFieldList.size() > 0) {
				for (Field field : annoFieldList) {
					FieldAnnotation anno = field
							.getAnnotation(FieldAnnotation.class);
					selectBuffer.append(anno.fieldName() + ",");
				}
				selectSql = selectBuffer.toString().substring(0,
						selectBuffer.length() - 1)
						+ " FROM " + tableName;
			}
		}
		return selectSql;
	}
}

 

实体类注释写法:

package net.tjnwdseip.entity;

import java.sql.Timestamp;

import net.tjnwdseip.util.FieldAnnotation;
import net.tjnwdseip.util.FieldType;

public class BaseEntity {

	@FieldAnnotation(fieldName="id",fieldType=FieldType.NUMBER,pk=true)
	private Integer id;
	
	@FieldAnnotation(fieldName="createDate",fieldType=FieldType.DATE, pk = false)
	private Timestamp createDate;
	
	@FieldAnnotation(fieldName="modifyDate",fieldType=FieldType.DATE, pk = false)
	private Timestamp modifyDate;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Timestamp getCreateDate() {
		return createDate;
	}

	public void setCreateDate(Timestamp createDate) {
		this.createDate = createDate;
	}

	public Timestamp getModifyDate() {
		return modifyDate;
	}

	public void setModifyDate(Timestamp modifyDate) {
		this.modifyDate = modifyDate;
	}

	public BaseEntity(Integer id, Timestamp createDate, Timestamp modifyDate) {
		super();
		this.id = id;
		this.createDate = createDate;
		this.modifyDate = modifyDate;
	}

	public BaseEntity() {
		super();
	}
}

 

package net.tjnwdseip.entity;

import java.sql.Timestamp;

import net.tjnwdseip.util.FieldAnnotation;
import net.tjnwdseip.util.FieldType;
import net.tjnwdseip.util.TableAnnotation;
/**
 * 
 * @ClassName: SysNetProxyCfg 
 * @Description: TODO(网络代理设置) 
 * @author LiYang 
 * @date 2012-5-2 下午4:13:08 
 *
 */
@TableAnnotation(tableName="sysNetProxyCfg")
public class SysNetProxyCfg extends BaseEntity {

	@FieldAnnotation(fieldName = "name", fieldType = FieldType.STRING, pk = false)
	private String name;
	
	@FieldAnnotation(fieldName = "type", fieldType = FieldType.STRING, pk = false)
	private String type;
	
	@FieldAnnotation(fieldName = "proxyHostIp", fieldType = FieldType.STRING, pk = false)
	private String proxyHostIp;
	
	@FieldAnnotation(fieldName = "proxyPort", fieldType = FieldType.NUMBER, pk = false)
	private Integer proxyPort;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getProxyHostIp() {
		return proxyHostIp;
	}

	public void setProxyHostIp(String proxyHostIp) {
		this.proxyHostIp = proxyHostIp;
	}

	public Integer getProxyPort() {
		return proxyPort;
	}

	public void setProxyPort(Integer proxyPort) {
		this.proxyPort = proxyPort;
	}

	public SysNetProxyCfg(Integer id, Timestamp createDate,
			Timestamp modifyDate, String name, String type, String proxyHostIp,
			Integer proxyPort) {
		super(id, createDate, modifyDate);
		this.name = name;
		this.type = type;
		this.proxyHostIp = proxyHostIp;
		this.proxyPort = proxyPort;
	}

	public SysNetProxyCfg() {
		super();
	}
}

 

测试类:

package net.tjnwdseip.demo;

import java.sql.Timestamp;
import java.util.HashMap;

import net.tjnwdseip.entity.SysNetProxyCfg;
import net.tjnwdseip.util.CreateSqlTools;

public class DemoTest {

	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SysNetProxyCfg netProxyCfg = new SysNetProxyCfg(1, Timestamp.valueOf("2012-05-04 14:45:35"), null, "netProxyCfgName", "netProxyCfgType", "000.000.000.000", 0);
		HashMap<String, String> fixedParams=new HashMap<String,String>();
		fixedParams.put("createDate", "NOW()");
		fixedParams.put("modifyDate", "NOW()");
		System.out.println(CreateSqlTools.getDeleteSql(netProxyCfg));
		System.out.println(CreateSqlTools.getDeleteSql(netProxyCfg, true));
		System.out.println(CreateSqlTools.getInsertSql(netProxyCfg));
		System.out.println(CreateSqlTools.getInsertSql(netProxyCfg, fixedParams));
		System.out.println(CreateSqlTools.getSelectAllSql(netProxyCfg));
		System.out.println(CreateSqlTools.getUpdateSql(netProxyCfg));
		System.out.println(CreateSqlTools.getUpdateSql(netProxyCfg, true));
		System.out.println(CreateSqlTools.getUpdateSql(netProxyCfg, true, fixedParams));
	}

}

 

测试结果:

DELETE FROM sysNetProxyCfg WHERE id=1 AND createDate='2012-05-04 14:45:35.0' AND name='netProxyCfgName' AND type='netProxyCfgType' AND proxyHostIp='000.000.000.000' AND proxyPort=0
DELETE FROM sysNetProxyCfg WHERE id=1
INSERT INTO sysNetProxyCfg (createDate,name,type,proxyHostIp,proxyPort) VALUES ('2012-05-04 14:45:35.0','netProxyCfgName','netProxyCfgType','000.000.000.000',0)
INSERT INTO sysNetProxyCfg (modifyDate,createDate) VALUES (NOW(),NOW())
SELECT id,createDate,modifyDate,name,type,proxyHostIp,proxyPort FROM sysNetProxyCfg
UPDATE sysNetProxyCfg SET createDate='2012-05-04 14:45:35.0',name='netProxyCfgName',type='netProxyCfgType',proxyHostIp='000.000.000.000',proxyPort=0
UPDATE sysNetProxyCfg SET createDate='2012-05-04 14:45:35.0',name='netProxyCfgName',type='netProxyCfgType',proxyHostIp='000.000.000.000',proxyPort=0 WHERE id=1
UPDATE sysNetProxyCfg SET modifyDate=NOW(),createDate=NOW() WHERE id=1

 

分享到:
评论

相关推荐

    根据表结构自动生成JavaBean,史上最强最专业的表结构转JavaBean的工具(第12版)

    于是一怒之下,自己动手丰衣足食,就自己用Swing写了一个通过数据库的表生成JavaBean的工具,支持MySQL、Oracle、SQLServce、PostgreSQL,完美支持JPA注解,可以同时生成Entity和DTO,可以自动去除表前缀,并支持...

    sql2entity:MySQL转换成Java实体类的小公举

    一款开源SQL语句转换成Java 实体类的小工具 需求起源 因为公司之前使用JPA,先写实体类再生产数据库建表语句,这样会有一个问题,数据建表语句都是没有注释的,对于新来的同事非常不友好,同时在开发中需要看字段...

    vs2005代码生成工具

    2、 生成基于实体类的数据更新语句,有新增、删除、修改,根据索引查询,读取列表等,简化基本的数据操作; 3、 生成更新及查询的存储过程,符合最新代码规范,增删改,根据ID查,根据索引查,分页查,查询...

    精通sql结构化查询语句

    1.5 SQL开发环境 1.5.1 SQL环境介绍 1.5.2 SQL的层次结构 1.5.3 SQL环境中的对象 1.5.4 SQL环境中的程序系统 1.6 SQL语句基础 1.6.1 SQL常量 1.6.2 SQL表达式 1.6.3 SQL数据类型 1.6.4 注释符 1.6.5 批处理 1.6.6 ...

    kellerMapper.jar

    SqlFieldReader.java:Sql 字段解析类,用于解析实体类中的自定义注解,为生成 Sql 语句服务 TypeCaster.java:类型转换,用于将 Java 中的数据类型转换成相应的 MySql 数据类型 util:工具类相关 Console.java...

    .Net十大必备工具之一

    可以用它来生成ORM的实体类,存储过程,SQL语句等。 7. Reflector for .NET Reflector for .NET是一个面向 Microsoft .NET Framework 的免费类浏览器、分析器和DLL反编译器。 8. The Regulator the regulator是很...

    .Net十大必备工具之二

    可以用它来生成ORM的实体类,存储过程,SQL语句等。 7. Reflector for .NET Reflector for .NET是一个面向 Microsoft .NET Framework 的免费类浏览器、分析器和DLL反编译器。 8. The Regulator the regulator是很...

    动软.Net代码自动生成器(Codematic)

    软件名称:动软.Net代码自动生成器(Codematic) 软件版本:1.9.7.2 (2006.4.14) 软件容量:2.65 MB 软件分类:开发工具 软件性质:国产软件 / 简体中文 / 免费软件 应用平台:WinNT/2000/XP...

    asp.net知识库

    直接从SQL语句问题贴子数据建表并生成建表语句的存储过程 从SQL中的一个表中导出HTML文件表格 获取數据库表的前N条记录 几段SQL Server语句和存储过程 生成表中的数据的脚本 最详细的SQL注入相关的命令整理 Oracle ...

    ASP.NET Night Words

    7.9 分页查询sql语句 111 7.10 总结 114 第8章 数据绑定控件 115 8.1 dropdownlist控件 116 8.2 listbox控件 118 8.3 数据绑定表达式 120 8.4 gridview控件 122 8.5 datalist控件 133 8.6 repeater控件 136 ...

    亮剑.NET深入体验与实战精要2

    5.3 常用经典SQL语句 224 5.4 事务处理 226 5.4.1 SQL和存储过程级别的事务 227 5.4.2 ADO.NET级别的事务 229 5.4.3 ASP.NET页面级别的事务 230 5.4.4 企业级服务COM+事务 231 5.4.5 System.Transactions 事务处理...

    亮剑.NET深入体验与实战精要3

    5.3 常用经典SQL语句 224 5.4 事务处理 226 5.4.1 SQL和存储过程级别的事务 227 5.4.2 ADO.NET级别的事务 229 5.4.3 ASP.NET页面级别的事务 230 5.4.4 企业级服务COM+事务 231 5.4.5 System.Transactions 事务处理...

    java初学者必看

    最近正在学习Java,也买了很多的有关Java方面的书籍,其中发现《跟我学Java》这本书,都的很不错啊,所以顺便拿电脑把这本书的目录敲了下来,与大家分享。...18.3.1 实体类 18.3.2 数据处理 18.3.3 权限处理

    乐优商城.xmind

    它用于注释实体类,映射超类或可嵌入类的属性或字段。 @Column(name = "'numeric'") 用来标识实体类中属性与数据表中字段的对应关系 name 定义了被标注字段在数据库表中所对应字段的名称; mapper service ...

Global site tag (gtag.js) - Google Analytics