SimplifiedHibernate:简化了的Hibernate
我的目的是实现下Hibernate中增删改查、缓存的核心功能。虽然基本功能实现了,但可能还有好多Bug,欢迎点评拍砖,没准能在一片谩骂声中取得意想不到的进步,:)
// DatabaseAccess.java
package com.dsp.core; import java.io.IOException;
import java.util.*; /**
* 数据库访问操作类
* @author dsp
*/
public class DatabaseAccess {
// 数据库辅助帮助类实例
private DatabaseHelper databaseHelper = new DatabaseHelper();
// DatabaseAccess类的泛型帮助类实例
private GenericityHelper genericityHelper = new GenericityHelper(); /**
* 向数据库添加object
* @param object 待添加的对象
* @return 若成功向数据库添加object,则返回数据库中object对应记录的id号,否则,返回-1
*/
@SuppressWarnings("unchecked")
public synchronized int add(Object object) {
// object为空
if(null == object)
return -1; List<String> columns = genericityHelper.getAllFieldNames(object);
Map<String, Object> columnToValues = genericityHelper.getFieldValues(columns, object); /*
* 拼接带占位符的SQL语句
*/
String className = genericityHelper.getClassName(object).toLowerCase();
String sql_0 = "insert into " + className + "(";
for(int index = 0; index < columns.size(); ++index) {
sql_0 += columns.get(index) + ",";
}
String sql_1 = sql_0.substring(0, sql_0.length() - 1) + ") values(";
// 设置占位符
for(int index = 0; index < columns.size(); ++index) {
sql_1 += "?,";
}
String sql_2 = sql_1.substring(0, sql_1.length() - 1);
sql_2 += ");"; /*
* 设置相应参数
*/
List<Object> params = new LinkedList<Object>();
for(int index = 0; index < columns.size(); ++index) {
String fieldName = columns.get(index);
if("id".equals(fieldName))
params.add(index, 0);
else
params.add(index, columnToValues.get(fieldName));
} // 执行插入
int result = databaseHelper.singleTableUpdate(sql_2, params, object.getClass()); // 若插入成功
if(result > 0) {
String tableName = genericityHelper.getClassName(object);
List<Object> targetList = (List<Object>) databaseHelper.getCachedData(tableName, object.getClass());
Object lastObject = targetList.get(targetList.size() - 1);
Object value = genericityHelper.getSpecifiedFieldValue("id", lastObject);
int id = Integer.parseInt(value.toString());
return id;
} else {
return -1;
}
} /**
* 从数据库中删除object
* @param object 待删除的对象
* @return 成功删除,返回true;否则返回false
*/
public synchronized boolean delete(Object object) {
// 对象为空
if(null == object)
return false; /*
* 拼接带占位符的SQL语句
*/
String className = genericityHelper.getClassName(object);
List<String> columns = genericityHelper.getAllFieldNames(object);
Map<String, Object> columnToValues = genericityHelper.getFieldValues(columns, object);
String sql = "delete from " + className + " where id = " + columnToValues.get("id") + ";"; // 执行删除操作
int result = databaseHelper.singleTableUpdate(sql, null, object.getClass());
if(result > 0)
return true;
else
return false;
} /**
* 更新数据库中德object对象
* @param object 要更新的对象
* @return 成功返回true,否则返回false
*/
public synchronized boolean update(Object object) {
// 对象为空
if(null == object)
return false; String className = genericityHelper.getClassName(object);
String sql_0 = "update " + className + " set "; List<Object> params = new ArrayList<Object>();
List<String> columns = genericityHelper.getAllFieldNames(object);
Map<String, Object> columnToValues = genericityHelper.getFieldValues(columns, object); /*
* 拼接带占位符的SQL语句
*/
for(int index = 0; index < columns.size(); ++index) {
String field = columns.get(index).toString();
if(field.equals("id"))
continue;
sql_0 += field + "=?,";
params.add(columnToValues.get(field));
} String sql_1 = sql_0.substring(0, sql_0.length() - 1) + " where id=?;";
params.add(columnToValues.get("id")); // 执行更新操作
int result = databaseHelper.singleTableUpdate(sql_1, params, object.getClass());
if(result <= 0)
return false;
else
return true;
} /**
* 从数据库中查询出所有的clazz记录,得到clazz记录的一份副本(深拷贝),使用时要求对应的Java Bean实现Serializable接口
* @param clazz 数据库表名映射的Java Bean反射实例
* @return 查询到的记录的链表
* @throws IOException
* @throws ClassNotFoundException
*/
@SuppressWarnings("unchecked")
public synchronized List<?> getAll(Class<?> clazz) {
List<?> resultsList = null;
try {
String className = genericityHelper.getClassName(clazz);
List<Object> tempResults = (List<Object>) databaseHelper.getCachedData(className, clazz);
resultsList = genericityHelper.deepClone(tempResults);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return resultsList;
} }
// DatabaseHelper.java
package com.dsp.core; import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import com.dsp.util.Log; /**
* 数据库JDBC操作辅助帮助类
* @author dsp
*/
public class DatabaseHelper {
// 已缓存了的数据链表
private static Map<String, List<Object>> cachedData = new HashMap<String, List<Object>>(); // JDBC连接
private Connection connection;
// 预编译对象
private PreparedStatement pstmt; /**
* 静态块,用来加载驱动
*/
static{
try {
Class.forName(LoadDBConfigFile.getInstance().getProperty("driverClassName"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
Log.log.error(e.toString());
}
} /**
* 获取连接
*/
private Connection getConnection() {
try {
// 手动创建JDBC连接
connection = DriverManager.getConnection(LoadDBConfigFile.getInstance().getProperty("url"), LoadDBConfigFile.getInstance().getProperty("username"), LoadDBConfigFile.getInstance().getProperty("password"));
if(connection == null) {
System.out.println("Error!!!Failed to connect database!");
System.exit(-1);
}
} catch (Exception e) {
Log.log.error(e.toString());
}
return connection;
} /**
* 关闭所有与JDBC相关的连接
* 顺序:先进后出
*/
private void closeAllConnections(Connection connection, PreparedStatement pstmt, ResultSet resultSet) {
if(pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
Log.log.error(e.toString());
}
}
if(connection != null) {
try {
connection.close();
} catch (SQLException e) {
Log.log.error(e.toString());
}
}
} /**
* 填充PreparedStatement对象的sql语句中的占位符
* @param pstmt PreparedStatement对象
* @param params 填充PreparedStatement对象中sql语句占位符的参数链表
* #######################################################################
* 参数化查询(Parameterized Query 或 Parameterized Statement)是指在设计与
* 数据库链接并访问数据时,在需要填入数值或数据的地方,使用参数 (Parameter) 来给值,
* 这个方法目前已被视为最有效可预防SQL注入攻击(SQL Injection) 的攻击手法的防御方式。
*/
private void replacePlaceholder(PreparedStatement pstmt, List<Object> params) {
if((pstmt != null) && (params != null) && (params.size() > 0)) {
for(int index = 0; index < params.size(); ++index) {
Object obj = params.get(index);
try {
if(obj == null) {
// 若为null。//待优化处,减少拼接的SQL语句长度
pstmt.setNull(index + 1, Types.INTEGER);
} else if("java.util.Date".equals(obj.getClass().getName())) {
pstmt.setDate(index + 1, new java.sql.Date(((java.util.Date) params.get(index)).getTime()));
} else if("java.lang.Double".equals(obj.getClass().getName())) {
pstmt.setDouble(index + 1, (Double) params.get(index));
} else if("java.lang.Integer".equals(obj.getClass().getName())) {
pstmt.setInt(index + 1, (Integer) params.get(index));
} else if("java.lang.Boolean".equals(obj.getClass().getName())) {
pstmt.setBoolean(index + 1, (Boolean) params.get(index));
} else if("javax.sql.rowset.serial.SerialBlob".equals(obj.getClass().getName())) {
pstmt.setBlob(index + 1, (Blob) params.get(index));
} else {
pstmt.setString(index+1, (String)params.get(index));
}
} catch (SQLException e) {
Log.log.error(e.toString());
}
}
}
} /**
* 打印输出SQL语句。
* 若成功,则是刚执行过的SQL语句;
* 失败则是致使数据库系统抛出异常的非法语句。
* @param pstmt 预编译SQL语句对象
*/
private void printExecutedSQL(PreparedStatement pstmt) {
String executedSQL = pstmt.toString();
System.out.println("====>" + executedSQL);
} /**
* 该表的数据是否已缓存
* @param tableName 表明
* @return 已缓存:true 否则返回 false
*/
private boolean isCached(String tableName) {
List<Object> tempList = cachedData.get(tableName);
if(tempList == null) {
return false;
}
return true;
} /**
* 根据键名获取对应已缓存的数据
* @param classNameOrTableName 取数据用的键名
* @return 缓存的数据链表
*/
public List<?> getCachedData(String classNameOrTableName, Class<?> clazz) {
if(isCached(classNameOrTableName)) {
return cachedData.get(classNameOrTableName);
} else {
// 若数据不在缓存中,则向数据库发送查询请求
String sql = "select * from " + classNameOrTableName + ";";
return this.singleTableQuery(sql, null, clazz);
}
} /**
* 对单表进行更新操作
* @param sql 带占位符的SQL语句
* @param params 用户填充SQL语句中的占位符的参数
* @return 执行结果:>0 成功 <=0 失败
*/
public synchronized int singleTableUpdate(String sql, List<Object> params, Class<?> clazz) {
connection = getConnection();
int result = 0;
try {
// 预编译对象
pstmt = connection.prepareStatement(sql);
replacePlaceholder(pstmt, params);
result = pstmt.executeUpdate();
// 放在此处是出于打印的语句与数据库实际操作的顺序一致性
printExecutedSQL(pstmt); // 更新缓存
String className = new GenericityHelper().getClassName(clazz);
String querySQL = "select * from " + className + ";";
this.singleTableQuery(querySQL, null, clazz);
} catch (SQLException e) {
try {
// 出错则打印SQL语句并回滚
printExecutedSQL(pstmt);
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
// 记录异常
e.printStackTrace();
Log.log.error(e.toString());
} finally {
closeAllConnections(connection, pstmt, null);
}
return result;
} /**
*
* @param sql 查询语句语句,可以含有占位符
* @param params 填充占位符的参数集
* @param clazz 泛型类型所对应的反射对象
* @param <T> 泛型:即你要得到的集合中存的对象的类型
* @return 存储查询到的所有对象链表
*/
@SuppressWarnings({ "unchecked" })
private synchronized <T> List<Object> singleTableQuery(String sql, List<Object> params, Class<T> clazz) {
// 若clazz为空
if(null == clazz) {
return null;
} /*
* 最新数据还未缓存,所以执行查询,检出数据库中的数据
*/
List<T> resultList = new ArrayList<T>();
connection = getConnection();
ResultSet resultSet = null; try {
// 预编译SQL语句对象
pstmt = connection.prepareStatement(sql);
replacePlaceholder(pstmt, params);
resultSet = pstmt.executeQuery(); ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
String[] columnNames = new String[resultSetMetaData.getColumnCount()]; for(int index = 0; index < columnNames.length; ++index) {
columnNames[index] = resultSetMetaData.getColumnName(index + 1);
} while(resultSet.next()) {
T temp = (T) clazz.newInstance();
for(int index = 0; index < columnNames.length; ++index) {
String targetMethdName = "set" + columnNames[index];
Method[] methods = clazz.getMethods();
if((methods != null) && (methods.length > 0)) {
for(Method method : methods) {
String tempMethodName = method.getName();
if(targetMethdName.equalsIgnoreCase(tempMethodName)) {
Object tempObject = resultSet.getObject(columnNames[index]);
if(tempObject != null) {
String columnTypeName = tempObject.getClass().getName();
if("java.lang.Integer".equals(columnTypeName)) {
method.invoke(temp, resultSet.getInt(columnNames[index]));
} else if("java.sql.Date".equals(columnTypeName)) {
method.invoke(temp, resultSet.getDate(columnNames[index]));
} else if("java.lang.Double".equals(columnTypeName)) {
method.invoke(temp, resultSet.getDouble(columnNames[index]));
} else if("java.lang.Boolean".equals(columnTypeName)) {
method.invoke(temp, resultSet.getBoolean(columnNames[index]));
} else {
method.invoke(temp, resultSet.getString(columnNames[index]));
}
}
break;
}
}
}
}
resultList.add(temp);
}
} catch (Exception e) {
e.printStackTrace();
Log.log.equals(e.toString());
} finally {
printExecutedSQL(pstmt);
closeAllConnections(connection, pstmt, resultSet);
} // 缓存最新数据
String tableName = new GenericityHelper().getClassName(clazz);
cachedData.remove(tableName);
cachedData.put(tableName, (List<Object>) resultList); return (List<Object>) resultList;
} }
// GenericityHelper.java
package com.dsp.core; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import com.dsp.util.Log; /**
* DatabaseAccess类的辅助帮助类
* 声明:
* 本来这个类的所有方法完全可安置到DatabaseAccess类中,从数据耦合
* 这个层面上来讲,DatabaseAccess类有太多的数据处理需要此类中的方法;
* 但考虑到代码都放到一个类中就显得代码有点冗长了,可以适时调整代码位置。
* @author dsp
*/
public class GenericityHelper {
/**
* 获取对象object的简短类名
* @param object 待操作的对象
* @return object对象所对应的类名
*/
public String getClassName(Object object) {
Class<?> clazz = getReflectClass(object);
String classFullName = getClassFullName(clazz);
return classFullName.substring(classFullName.lastIndexOf(".") + 1).toLowerCase();
} /**
* 重载方法
* 获取对象object的简短类名
* @param clazz 反射类实例
* @return 反射类实例所对应的类名
*/
public String getClassName(Class<?> clazz) {
String classFullName = getClassFullName(clazz);
return classFullName.substring(classFullName.lastIndexOf(".") + 1).toLowerCase();
} /**
* 获取对象所有的的字段名
* @param object 操作的对象
* @return object所有的字段名
*/
public List<String> getAllFieldNames(Object object) {
Class<?> clazz = getReflectClass(object);
Field[] fields = clazz.getDeclaredFields();
List<String> columns = new ArrayList<String>();
for(int index = 0; index < fields.length; ++index) {
columns.add(index, fields[index].getName().toString());
}
return columns;
} /**
* 获取所有字段对应的值:键值对
* @param columns 所有的字段名
* @param object 值来源对象
* @return object所有的字段对应的值
*/
public Map<String, Object> getFieldValues(List<String> columns, Object object) {
Map<String, Object> columnToValues = new HashMap<String, Object>();
for(int index = 0; index < columns.size(); ++index) {
String fieldName = columns.get(index).toString();
columnToValues.put(fieldName, getSpecifiedFieldValue(fieldName, object));
}
return columnToValues;
} /**
* 根据类字段名获取该字段对应的值
* @param fieldName 字段名
* @param object 数据源对象
* @return object中fieldName字段对应的值
*/
public Object getSpecifiedFieldValue(String fieldName, Object object) {
List<String> methodNames = generateMethodNames(fieldName);
Method targetMethod = getExistedMethod(methodNames, getReflectClass(object));
Object value = getValueBySpecifiedMethod(targetMethod, object);
return dataCastType(value);
} /**
* 获取对象object的反射类实例
* @param object 操作对象
* @return object对象的反射类实例
*/
private Class<? extends Object> getReflectClass(Object object) {
return object.getClass();
} /**
* 获取反射类实例的类全名
* @param clazz 反射类实例
* @return clazz的类全名
*/
private String getClassFullName(Class<?> clazz) {
return clazz.getName();
} /**
* 获取object对象的指定函数返回的值
* @param targetMethod 指定的函数
* @param object 操作的对象
* @return object对象的targetMethod函数返回的值
*/
private Object getValueBySpecifiedMethod(Method targetMethod, Object object) {
Object value = null;
try {
value = targetMethod.invoke(object, new Object[] {});
} catch (IllegalAccessException e) {
e.printStackTrace();
Log.log.error(e.toString());
} catch (InvocationTargetException e) {
e.printStackTrace();
Log.log.error(e.toString());
}
return value;
} /**
* 数据转换
* @param value 待转换的值
* @return 转换后的值
*/
private Object dataCastType(Object value) {
if(value instanceof Timestamp)
value = Timestamp.valueOf(value.toString());
return value;
} /**
* 判断methodName是否是对象中存在的函数名
* @param methodName 待校验的可能的函数名
* @param clazz 反射类实例
* @return 若methodName是clazz中的函数名,返回true,否则返回false
*/
private boolean isExistedMethodName(String methodName, Class<?> clazz) {
Method[] methods = clazz.getMethods();
for(Method method : methods) {
if(method.getName().equals(methodName))
return true;
}
return false;
} /**
* 根据可能的函数名字检索clazz对象存在的函数
* @param methodNames 函数名字链表
* @param clazz 反射类实例
* @return 在clazz对象中根据函数名字检索到的函数
*/
private Method getExistedMethod(List<String> methodNames, Class<?> clazz) {
for(String methodName : methodNames) {
if(isExistedMethodName(methodName, clazz)) {
try {
Method targetMethod = clazz.getMethod(methodName, new Class[] {});
if(targetMethod != null) {
return targetMethod;
}
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
Log.log.error(e.toString());
}
}
}
return null;
} /**
* 根据字段名生成可能的目标函数名
* @param fieldName 字段名
* @return 根据fieldName生成的所有可能的目标函数名,将其存放在链表中
*/
private List<String> generateMethodNames(String fieldName) {
List<String> methodNames = new ArrayList<String>();
String firstLetter = fieldName.substring(0, 1).toUpperCase();
String postfix = firstLetter + fieldName.substring(1); /*
* IDE自动生成的getter函数前缀不一定都是"get"
*/
// 方法是”getXyz()“
String methodPrefixGet = "get" + postfix;
methodNames.add(methodPrefixGet);
// 方法名是“isXyz()”
String methodPrefixIs = "is" + postfix;
methodNames.add(methodPrefixIs); return methodNames;
} /**
* 深拷贝List<Object>,要求Object已实现Serializable接口
* @param sourceList 源List
* @return 源List的一份副本
* @throws IOException
* @throws ClassNotFoundException
*/
@SuppressWarnings("unchecked")
public List<Object> deepClone(List<Object> sourceList) throws IOException, ClassNotFoundException {
ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutStream = new ObjectOutputStream(byteOutStream);
objectOutStream.writeObject(sourceList); ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteOutStream.toByteArray());
ObjectInputStream objectInputStream =new ObjectInputStream(byteInputStream);
List<Object> destList = (List<Object>) objectInputStream.readObject();
return destList;
} }
// LoadDBConfigFile.java
package com.dsp.core; import java.io.IOException;
import java.io.InputStream;
import java.util.Properties; import com.dsp.util.Log; /**
* 加载数据库配置文件
* @author dsp
*/
public class LoadDBConfigFile extends Properties {
private static final long serialVersionUID = 1907772550710288554L; private static LoadDBConfigFile instance = null; /**
* 对外提供一个工厂方法
* @return LoadDBConfigFile的全局唯一实例
*/
public synchronized static LoadDBConfigFile getInstance() {
if(instance != null) {
return instance;
} else {
instance = new LoadDBConfigFile();
return instance;
}
} /**
* 单例模式的核心:构造方法私有化
*/
private LoadDBConfigFile() {
// db.properties文件保存有基本的配置信息
// 通过类的反射实例找到并加载classpath路径下的指定资源文件,并将其生成一个输入流;
InputStream inputStream = this.getClass().getResourceAsStream("/db.properties");
try {
// 将输入流中的信息加载到类的当前对象中
this.load(inputStream);
} catch (IOException e) {
Log.log.error(e.toString());
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
Log.log.error(e.toString());
}
}
} }
// Log.java
package com.dsp.util; import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator; public class Log { public static Logger log; static {
PropertyConfigurator.configure("/log4j.properties");
log = Logger.getLogger(Log.class);
log.debug("debug");
log.error("error");
} }
// db.properties
- driverClassName=com.mysql.jdbc.Driver
- url=jdbc\:mysql\://127.0.0.1\:3306/retina
- username=root
- password=123456
// log4j.properties
- log4j.appender.stdout=org.apache.log4j.ConsoleAppender
- log4j.appender.stdout.Target=System.out
- log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
- log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %m%n
- log4j.appender.file=org.apache.log4j.FileAppender
- log4j.appender.file.File=retina.log
- log4j.appender.file.layout=org.apache.log4j.PatternLayout
- log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %m%n
- log4j.rootLogger=WARN,stdout,file
// DatabaseAccessTester.java 测试代码
import com.dsp.bean.MovieType;
import com.dsp.core.DatabaseAccess;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.List; /**
* Created by dsp on 14-3-9.
*/
public class DataBaseAccessTester {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// MovieType movieType = new MovieType();
// movieType.setId(6);
// movieType.setName("101010");
// new DatabaseAccess().add(movieType);
//
DatabaseAccess databaseAccess = new DatabaseAccess();
// List<MovieType> movieTypes = (List<MovieType>) databaseAccess.getAll(MovieType.class);
// for(MovieType movieType_ : movieTypes) {
// System.out.println(movieType_);
// }
//
// System.out.println("#############################################################");
//
// MovieType movieType_1 = new MovieType();
// movieType_1.setId(8);
// movieType_1.setName("888");
// new DatabaseAccess().update(movieType_1);
//
// System.out.println("#############################################################");
//
// List<MovieType> movieTypes_1 = (List<MovieType>) databaseAccess.getAll(MovieType.class);
// for(MovieType movieType_2 : movieTypes_1) {
// System.out.println(movieType_2);
// }
//
// System.out.println("#############################################################");
// System.out.println("#############################################################");
//
// MovieType movieType_2 = new MovieType();
// movieType_2.setId(9);
// movieType_2.setName("dsp");
// new DatabaseAccess().update(movieType_2);
//
// System.out.println("#############################################################"); // List<MovieType> movieTypes_22 = (List<MovieType>) databaseAccess.getAll(MovieType.class);
// movieTypes_22.remove(0);
// movieTypes_22.remove(3);
// movieTypes_22.add(new MovieType());
// for(MovieType movieType_22 : movieTypes_22) {
// System.out.println(movieType_22);
// }
//
// System.out.println("###############################################################");
//
// List<MovieType> movieTypeList_23 = (List<MovieType>) new DatabaseHelper().getCachedData("movietype", MovieType.class);
// for(MovieType movieType_22 : movieTypeList_23) {
// System.out.println(movieType_22);
// }
//
// System.out.println("#########################");
// System.out.println(movieTypes_22 == movieTypeList_23); // ##################################################################################
} }
^_^ ~
SimplifiedHibernate:简化了的Hibernate的更多相关文章
- 02.Hibernate映射基础
前言:Hibernate的核心功能是根据数据库到实体类的映射,自动从数据库绑定数据到实体类.使我们操作实体类(Java对象)就能对数据库进行增.删.查.改,而不用调用JDBC API使数据操作变得简单 ...
- java之Hibernate框架实现数据库操作
之前我们用一个java类连接MySQL数据库实现了数据库的增删改查操作---------MySQL篇: 但是数据库种类之多,除了MySQL,还有Access.Oracle.DB2等等,而且每种数据库语 ...
- Hibernate Tools插件的使用
Hibernate Tools是由JBoss推出的一个Eclipse综合开发工具插件,该插件可以简化ORM框架Hibernate,以及JBoss Seam,EJB3等的开发工作.Hib ...
- hibernate之单表映射
目录 第一章 Hibernate初识 1-1 课程介绍 1-2 什么是ORM 1-3 Hibnerate简介 1-4 开发前的准备 1-5 编写第一个Hibernate例子 1-6 创建hiberna ...
- Hibernate初探之单表映射——Hibernate概念及插件的安装
什么是ORM ORM(Object/Relationship Mapping):对象/关系映射 为什么要有ORM? 利用面向对象思想编写的数据库应用程序最终都是把对象信息保存在关系型数据库中,于是要编 ...
- Spring基础4
一.Spring的JDBC模板 Spring对持久层也提供了解决方案,ORM模块和JDBC模板 提高简化JDBC或Hibernate的模板 二.JDBC模板使用入门 1)引入jar包:Spring开发 ...
- Spring从认识到细化了解
目录 Spring的介绍 基本运行环境搭建 IoC 介绍: 示例使用: 使用说明: 使用注意: Bean的实例化方式 Bean的作用范围的配置: 补充: DI: 属性注入: 补充: IoC的注解方式: ...
- SSH框架简化(struts2+spring+hibernate)
目的: 通过对ssh框架有了基础性的学习,本文主要是使用注解的方式来简化ssh框架的代码编写. 注意事项: 1.运行环境:Windows 8-64位,Eclipse(开发工具),jdk1.8.0_91 ...
- hibernate使用注解简化开发
简述 在编写hibernate的时候,需要将实体类映射到数据库中的表.通常需要一个配置文件(hibernate.cfg.xml),一个实体类(XX.Java),还有一个映射文件(XX.hbm.xml) ...
随机推荐
- python map 详解
python中的map函数应用于每一个可迭代的项,返回的是一个结果list.如果有其他的可迭代参数传进来,map函数则会把每一个参数都以相应的处理函数进行迭代处理.map()函数接收两个参数,一个是函 ...
- 免费申请 Github 私有仓库--学生和教育人士的福利
免费申请 Github 私有仓库 -学生和教育人士的福利 Github 是全球知名的软件项目托管网站.在 Github 创建私有仓库是需要收费的,收费方案有多种,费用最小的方案是每月 7 美元的“微型 ...
- 图像的线性空间滤波matlab实现
1.线性空间滤波函数Z = imfilter(X,H,option1,option2,...) X为输入图像矩阵,H为m*n维的掩膜矩阵,H中的数据类型必须是double类型.掩膜矩阵可以是用户定义, ...
- [hihoCoder] #1081 : 最短路径·一
时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 万圣节的早上,小Hi和小Ho在经历了一个小时的争论后,终于决定了如何度过这样有意义的一天——他们决定去闯鬼屋! 在鬼屋门口 ...
- Clojure 下的 xpath 库
clj-xpath 项目网站 Github
- Android Gradle 引用本地 AAR 的几种方式
折衷方案: 1.方式2 - 不完美解决办法2 2.再使用"自定义Gradle代码"来减轻重复设置的问题. 自定义Gradle代码如下: repositories { flatDir ...
- FPGA三分频,五分频,奇数分频
我们在做FPGA设计时,有时会用到时钟频率奇数分频的频率,例如笔者FPGA的晶振为50M,当我们需要10M的时钟时,一种方式可以使用DCM或PLL获取,系统会内部分频到10M,但其实VERILOG内部 ...
- 【Android】3.2 基本地图功能
分类:C#.Android: 日期:2016-02-04 3.2 示例2--基本地图功能 一.简介 1.地图 地图展示:普通地图(2D,3D).卫星图和实时交通图. 地图操作:可通过接口或手势控制来实 ...
- 如何在 Ubuntu 和 CentOS 上启用 Nginx 的 HTTP/2 协议支持
HTTP/2 是 HTTP 网络协议的主要修订版本,其专注于 HTTP 协议的性能改进.HTTP/2 协议的目标是减少延迟,并且允许在 Web 浏览器和服务器之间的一个连接上并行发起多个请求,因此 W ...
- angular学习笔记(六)-非入侵式javascript
这篇主要讲解非入侵式javascript. 在传统的前端开发中,把js写在html中,称为入侵式的javascript: <span id="select_area" onc ...