A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 上海分校-小影 于 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);
    }
    }

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马