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) ...
随机推荐
- 在ubuntu中配置深度学习python图片分类实验环境
1 安装numpy,scipy, matplotlib, sudo apt-get install python-numpy sudo apt-get install python-scipy sud ...
- PHP位操作符
二进制怎么算 http://www.doc88.com/p-474114598610.html 这个涉及到系统底层,WEB开发中几乎没用到,知道下有这个东西就好了.底层的东西解释总是简单不了的. 变量 ...
- UVA - 11609 Teams (排列组合数公式)
In a galaxy far far awaythere is an ancient game played among the planets. The specialty of the game ...
- Viso Professional 2013版本激活(office 系列产品 -- visio 2013 / project 2013 破解工具 - KMSpico)
背景: 环境是 win7, 64 bit 装了 visio 2013 , 可以却不能用它来画图,在网上找了一些破解工具,大都不能解决问题.网上不靠谱的广告型文章太多了,比较头痛. 所幸,终于找到正确的 ...
- Lattice系列FPGA入门相关0(Lattice与Altera、Xilinx对比及入门)
需求说明:Lattice系统FPGA入门 内容 :Lattice与Altera.Xilinx对比 来自 :时间的诗 1.Lattice与Altera.Xilinx对比 latt ...
- 原来的debussy可以在win7的64位系统下运行吗
可以的,首先下载两个DLL:msvcr71.dll和msvcp71.dll,然后破解一下就可以了. https://zhidao.baidu.com/question/2419893614880017 ...
- 【Android】17.0 第17章 服务绑定—本章示例主界面
分类:C#.Android.VS2015: 创建日期:2016-03-03 一.简介 通过服务绑定(Bound Services),可以轻松实现后台服务与界面(UI)的交互. 二.本章示例主界面 1. ...
- copy 的实现原理与深浅拷贝
转自:http://bbs.9ria.com/thread-210322-1-1.html 首先,从copy开始说,简而言之,copy的目的就是生成一个新的实例,然后把其成员都按原实例赋值.对于非指针 ...
- laravel 代码维护, 使用php artisan使用应用程序处于维护状态
当应用程序处于维护的时候,我们可以暂时关闭程序,具体的做使用是使用php artisan downartisan 是laravel根目录下的一个程序,当执行了这个命令时,会调用 app/start/g ...
- java执行shell/cmd命令
try { Process p =Runtime.getRuntime().exec("chmod 777 /home/bomb/MoveToy/WebRoot/a.sh " ); ...