本帖最后由 上海分校-小影 于 2018-5-24 14:30 编辑
Hibernate原理模拟
1、基础环境搭建1.1创建数据库、表
/*创建客户表*/
CREATE TABLE `cst_customer` (
`cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
`cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
`cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
`cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
`cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
`cust_address` varchar(128) DEFAULT NULL COMMENT '客户联系地址',
`cust_phone` varchar(64) DEFAULT NULL COMMENT '客户联系电话',
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
1.2创建工程,引入依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.itcast</groupId>
<artifactId>hibernate</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.0.7.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
1.3创建实体类
/**
- 客户实体类
*/
public class Customer implements Serializable{
private static final long serialVersionUID = 1L;
private Long custId;
private String custName;
private String custSource;
private String custIndustry;
private String custLevel;
private String custAddress;
private String custPhone;
public Long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
@Override
public String toString() {
return "Customer [custId=" + custId + ", custName=" + custName + ", custSource=" + custSource
+ ", custIndustry=" + custIndustry + ", custLevel=" + custLevel + ", custAddress=" + custAddress
+ ", custPhone=" + custPhone + "]";
}
}
创建映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- name属性:指定实体类的全路径名
table属性:指定对应的表的名字,如果类名与表名一致,可以省略不写table属性
-->
<class name="cn.itcast.domain.Customer" table="cst_customer">
<!-- id标签:指定 实体类中哪个属性与表中的主键列对应
name属性:指定实体类中属性的名字
column属性:指定表中对应列的名字,如果属性名与列名一致,可以省略column属性
generator标签:指定主键的生成策略
class属性:指定具体的生成策略,native表示根据底层的数据库来选择,如果是mysql,就自动增长,
如果是orcale,就采用序列来维护主键
-->
<id name="custId" column="cust_id">
<generator class="native">
</generator>
</id>
<!-- property标签:指定除了主键属性以外的其它属性
name属性:指定属性名
column属性:指定表中对应的列名,如果属性名与列名一致,可以省略column属性
-->
<property name="custName" column="cust_name"></property>
<property name="custSource" column="cust_source"></property>
<property name="custIndustry" column="cust_industry"></property>
<property name="custLevel" column="cust_level"></property>
<property name="custAddress" column="cust_address"></property>
<property name="custPhone" column="cust_phone"></property>
</class>
</hibernate-mapping>
1.4创建hibernate的核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 配置数据库连接信息 -->
<!-- 配置数据库驱动类名 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 配置数据库连接地址 -->
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<!-- 数据库用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 数据库密码 -->
<property name="hibernate.connection.password">123456</property>
<!-- 配置数据库方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 打印sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化sql语句 -->
<property name="hibernate.format_sql">true</property>
<!-- 指定映射文件路径 -->
<mapping resource="cn/itcast/domain/Customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
1.5编写测试代码
public class TestHibernate {
@Test
public void test1() {
// 要保存的对象
Customer customer = new Customer();
customer.setCustName("传智播客");
customer.setCustIndustry("IT培训");
customer.setCustSource("网络营销");
customer.setCustLevel("VIP客户");
customer.setCustAddress("北京");
customer.setCustPhone("0108650123");
// 实例化Configuration的对象
Configuration cfg = new Configuration();
// 读取核心配置文件hibernate.cfg.xml
cfg.configure();
// 构造SessionFactory
SessionFactory sf = cfg.buildSessionFactory();
// 获取Session,类似于JDBC里的Connection
Session session = sf.openSession();
// 开启事务
Transaction tx = session.beginTransaction();
// 保存
session.save(customer);
// 提交事务
tx.commit();
// 释放资源
session.close();
sf.close();
}
}
2、原理模拟思路分析
自己封装一个类叫Session,模拟Hibernate中的Session;
在Session中封装一个方法叫save,模拟Hibernate中Session的save;
在save中要通过jdbc代码执行sql语句,故需要根据实体类通过反射生成sql语句;
原理模拟时,我们省略映射文件解析的过程,默认表名和类名一致,列名和属性名一致;
3、代码实现
创建实体类
public class Account {
private Long id;
private String name;
private Double money;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
}
模拟Session的保存
public class Session {
private static final String driver = "com.mysql.jdbc.Driver";
private static final String url = "jdbc:mysql://localhost:3306/hibernate";
private static final String username = "root";
private static final String password = "123456";
private static Map<String, String> map = new HashMap<String, String>();
/**
* 模拟Hibernate中Session的保存方法
*
* @param obj
* @throws Exception
*/
public void save(Object obj) throws Exception {
String sql = generateSQL(obj);// 调用生成sql语句的方法
System.out.println(sql);// 打印sql语句
Class.forName(driver);
Connection conn = DriverManager.getConnection(url, username, password);
PreparedStatement ps = conn.prepareStatement(sql);
Set<String> keys = map.keySet();
int i = 1;// 表示占位符的索引
for (String key : keys) {
// 获取属性对应的get方法
Method m = obj.getClass().getMethod(map.get(key));
// 通过反射调用get方法获取属性的值,作为占位符的值
ps.setObject(i, m.invoke(obj));
i++;// 占位符+1
}
ps.executeUpdate();// 指定插入语句
}
/**
* 生成sql语句的方法 insert into 表名(列名,列名,...) values(?,?,...)
*
* @param obj
* @return
* @throws SecurityException
* @throws NoSuchMethodException
*/
public static String generateSQL(Object obj) throws Exception {
// 获取实体类中所有的属性
Field[] fields = obj.getClass().getDeclaredFields();
// 向map中存放键值对:键是属性名,也就是列名;值是属性get方法的名字
for (int i = 0; i < fields.length; i++) {
map.put(fields.getName(),
"get" + fields.getName().substring(0, 1).toUpperCase() + fields.getName().substring(1));
}
String columns = "";// 存储列名
String values = "";// 存储?
Set<String> keys = map.keySet();
for (String key : keys) {
columns = columns + key + ",";// 拼接列名
values = values + "?,";
}
// 截取最后的逗号
if (columns.endsWith(",")) {
columns = columns.substring(0, columns.length() - 1);
values = values.substring(0, values.length() - 1);
}
// 获取实体类的表名
String tName = obj.getClass().getSimpleName();
// 拼接sql语句
String sql = "insert into " + tName + "(" + columns + ") values(" + values + ")";
return sql;
}
public static void main(String[] args) throws Exception {
//自己模拟的Session
Session session = new Session();
// 要保存的对象
Account account = new Account();
account.setName("张三");
account.setMoney(1000.0);
session.save(account);
}
}
|
|