成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

hibernate和jdbc的淵源

includecmath / 3390人閱讀

摘要:同時(shí),我們將語(yǔ)句預(yù)編譯在中,這個(gè)類(lèi)可以使用占位符,避免注入,當(dāng)然,后面說(shuō)到的的占位符的原理也是這樣,同時(shí),的占位符原理也是如此。的底層封裝了,比如說(shuō)為了防止注入,一般會(huì)有占位符,也會(huì)有響應(yīng)的占位符。

介紹jdbc

我們學(xué)習(xí)Java數(shù)據(jù)庫(kù)操作時(shí),一般會(huì)設(shè)計(jì)到j(luò)dbc的操作,這是一位程序員最基本的素養(yǎng)。jdbc以其優(yōu)美的代碼和高性能,將瞬時(shí)態(tài)的javabean對(duì)象轉(zhuǎn)化為持久態(tài)的SQL數(shù)據(jù)。但是,每次SQL操作都需要建立和關(guān)閉連接,這勢(shì)必會(huì)消耗大量的資源開(kāi)銷(xiāo);如果我們自行創(chuàng)建連接池,假如每個(gè)項(xiàng)目都這樣做,勢(shì)必搞死的了。同時(shí),我們將SQL語(yǔ)句預(yù)編譯在PreparedStatement中,這個(gè)類(lèi)可以使用占位符,避免SQL注入,當(dāng)然,后面說(shuō)到的hibernate的占位符的原理也是這樣,同時(shí),mybatis的#{}占位符原理也是如此。預(yù)編譯的語(yǔ)句是原生的SQL語(yǔ)句,比如更新語(yǔ)句:

private static int update(Student student) {
    Connection conn = getConn();
    int i = 0;
    String sql = "update students set Age="" + student.getAge() + "" where Name="" + student.getName() + """;
    PreparedStatement pstmt;
    try {
        pstmt = (PreparedStatement) conn.prepareStatement(sql);
        i = pstmt.executeUpdate();
        System.out.println("resutl: " + i);
        pstmt.close();
        conn.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return i;
}

上面的sql語(yǔ)句沒(méi)有使用占位符,如果我們少了varchar類(lèi)型的單引號(hào),就會(huì)保存失敗。在這種情況下,如果寫(xiě)了很多句代碼,最后因?yàn)橐粋€(gè)單引號(hào),導(dǎo)致代碼失敗,對(duì)于程序員來(lái)說(shuō),無(wú)疑是很傷自信心的事。如果涉及到了事務(wù),那么就會(huì)非常的麻煩,一旦一個(gè)原子操作的語(yǔ)句出現(xiàn)錯(cuò)誤,那么事務(wù)就不會(huì)提交,自信心就會(huì)跌倒低谷。然而,這僅僅是更新語(yǔ)句,如果是多表聯(lián)合查詢(xún)語(yǔ)句,那么就要寫(xiě)很多代碼了。具體的jdbc的操作,可以參考這篇文章:jdbc操作。

因而,我們?cè)诳隙ㄋ膬?yōu)點(diǎn)時(shí),也不應(yīng)該規(guī)避他的缺點(diǎn)。隨著工業(yè)化步伐的推進(jìn),每個(gè)數(shù)據(jù)庫(kù)往往涉及到很多表,每張表有可能會(huì)關(guān)聯(lián)到其他表,如果我們還是按照jdbc的方式操作,這無(wú)疑是增加了開(kāi)發(fā)效率。所以,有人厭倦這種復(fù)雜繁瑣、效率低下的操作,于是,寫(xiě)出了著名的hibernate框架,封裝了底層的jdbc操作,以下是jdbc的優(yōu)缺點(diǎn):

由上圖可以看見(jiàn),jdbc不適合公司的開(kāi)發(fā),公司畢竟以最少的開(kāi)發(fā)成本來(lái)創(chuàng)造更多的利益。這就出現(xiàn)了痛點(diǎn),商機(jī)伴隨著痛點(diǎn)的出現(xiàn)。因而,應(yīng)世而生了hibernate這個(gè)框架。即便沒(méi)有hibernate的框架,也會(huì)有其他框架生成。hibernate的底層封裝了jdbc,比如說(shuō)jdbc為了防止sql注入,一般會(huì)有占位符,hibernate也會(huì)有響應(yīng)的占位符。hibernate是orm(object relational mapping)的一種,即對(duì)象關(guān)系映射。

對(duì)象關(guān)系映射

通俗地來(lái)說(shuō),對(duì)象在pojo中可以指Javabean,關(guān)系可以指MySQL的關(guān)系型數(shù)據(jù)庫(kù)的表字段與javabean對(duì)象屬性的關(guān)系。映射可以用我們高中所學(xué)的函數(shù)映射,即Javabean瞬時(shí)態(tài)的對(duì)象映射到數(shù)據(jù)庫(kù)的持久態(tài)的數(shù)據(jù)對(duì)象。我們都知道javabean在內(nèi)存中的數(shù)據(jù)是瞬時(shí)狀態(tài)或游離狀態(tài),就像是宇宙星空中的一顆顆行星,除非行星被其他行星所吸引,才有可能不成為游離的行星。瞬時(shí)狀態(tài)(游離狀態(tài))的javabean對(duì)象的生命周期隨著進(jìn)程的關(guān)閉或者方法的結(jié)束而結(jié)束。如果當(dāng)前javabean對(duì)象與gcRoots沒(méi)有直接或間接的關(guān)系,其有可能會(huì)被gc回收。我們就沒(méi)辦法長(zhǎng)久地存儲(chǔ)數(shù)據(jù),這是一個(gè)非常頭疼的問(wèn)題。假如我們使用文件來(lái)存儲(chǔ)數(shù)據(jù),但是文件操作起來(lái)非常麻煩,而且數(shù)據(jù)格式不是很整潔,不利于后期的維護(hù)等。因而,橫空出世了數(shù)據(jù)庫(kù)。我們可以使用數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù),數(shù)據(jù)庫(kù)中的數(shù)據(jù)才是持久數(shù)據(jù)(數(shù)據(jù)庫(kù)的持久性),除非人為的刪除。這里有個(gè)問(wèn)題——怎么將瞬時(shí)狀態(tài)(游離狀態(tài))的數(shù)據(jù)轉(zhuǎn)化為持久狀態(tài)的數(shù)據(jù),肯定需要一個(gè)連接Javabean和數(shù)據(jù)庫(kù)的橋梁,于是乎就有了上面的jdbc。

多帶帶來(lái)說(shuō)mysql,mysql是一個(gè)遠(yuǎn)程服務(wù)器。我們?cè)谙騧ysql傳輸數(shù)據(jù)時(shí),并不是對(duì)象的方式傳輸,而是以字節(jié)碼的方式傳輸數(shù)據(jù)。為了保證數(shù)據(jù)準(zhǔn)確的傳輸,我們一般會(huì)序列化當(dāng)前對(duì)象,用序列號(hào)標(biāo)志這個(gè)唯一的對(duì)象。如果,我們不想存儲(chǔ)某個(gè)屬性,它是有數(shù)據(jù)庫(kù)中的數(shù)據(jù)拼接而成的,我們大可不用序列化這個(gè)屬性,可以使用Transient來(lái)修飾。比如下面的獲取圖片的路徑,其實(shí)就是服務(wù)器圖片的文件夾地址和圖片的名稱(chēng)拼接而成的。當(dāng)然,你想存儲(chǔ)這個(gè)屬性,也可以存儲(chǔ)這個(gè)屬性。我們有時(shí)候圖片的路由的字節(jié)很長(zhǎng),這樣會(huì)占用MySQL的內(nèi)存。因而,學(xué)會(huì)取舍,未嘗不是一個(gè)明智之舉。

@Entity
@Table(name = "core_picture")
public class Picture extends BaseTenantObj {

   。。。。

  @Transient
    public String getLocaleUrl() {
        return relativeFolder.endsWith("/") ? relativeFolder + name : relativeFolder + "/" + name;
    }

 。。。。

}

網(wǎng)上流傳盛廣的對(duì)象關(guān)系映射的框架(orm)有hibernate、mybatis等。重點(diǎn)說(shuō)說(shuō)hibernate和mybatis吧。hibernate是墨爾本的一位厭倦重復(fù)的javabean的程序員編寫(xiě)而成的,mybatis是appache旗下的一個(gè)子產(chǎn)品,其都是封裝了jdbc底層操作的orm框架。但hibernate更注重javabean與數(shù)據(jù)表之間的關(guān)系,比如我們可以使用注解生成數(shù)據(jù)表,也可以通過(guò)注解的方式設(shè)置字段的類(lèi)型、注釋等。他將javabean分成了游離態(tài)、瞬時(shí)態(tài)、持久態(tài)等,hibernate根據(jù)這三種狀態(tài)來(lái)觸及javabean對(duì)象的數(shù)據(jù)。而mybatis更多的是注重SQL語(yǔ)句的書(shū)寫(xiě),也就是說(shuō)主要是pojo與SQL語(yǔ)句的數(shù)據(jù)交互,對(duì)此,Hibernate對(duì)查詢(xún)對(duì)象有著良好的管理機(jī)制,用戶(hù)無(wú)需關(guān)心SQL。一旦SQL語(yǔ)句的移動(dòng),有可能會(huì)影響字段的不對(duì)應(yīng),因而,mybatis移植性沒(méi)有hibernate好。mybatis接觸的是底層SQL數(shù)據(jù)的書(shū)寫(xiě),hibernate根據(jù)javabean的參數(shù)來(lái)生成SQL語(yǔ)句,再將SQL查詢(xún)的結(jié)果封裝成pojo,因而,mybatis的性能相來(lái)說(shuō)優(yōu)于hibernate,但這也不是絕對(duì)的。性能還要根據(jù)你的表的設(shè)計(jì)結(jié)構(gòu)、SQL語(yǔ)句的封裝、網(wǎng)絡(luò)、帶寬等等。我只是拋磚引玉,它們具體的區(qū)別,可以參考這篇文檔。mybatis和hibernate的優(yōu)缺點(diǎn)。

hibernate和mybatis之間的區(qū)別,也是很多公司提問(wèn)面試者的問(wèn)題。但是真正熟知他們區(qū)別的人,一般是技術(shù)選型的架構(gòu)師。如果你只是負(fù)責(zé)開(kāi)發(fā),不需要了解它們的區(qū)別,因?yàn)樗麄兌挤庋b了jdbc。所以,你不論使用誰(shuí),都還是比較容易的。然而,很多公司的HR提問(wèn)這種問(wèn)題很死板,HR并不懂技術(shù),他們只是照本宣科的提問(wèn)。如果你照本宣科的回答,它們覺(jué)著你很厲害。但是,如果是一個(gè)懂技術(shù)的人提問(wèn)你,如果你只是臨時(shí)背了它們的區(qū)別,而沒(méi)有相應(yīng)的工作經(jīng)驗(yàn),他們會(huì)問(wèn)的讓你手足無(wú)措。

hibernate講解

因?yàn)槲覀児臼褂玫氖莌ibernate,我在這里簡(jiǎn)單地介紹下hibernate。但相對(duì)于jdbc來(lái)說(shuō),hibernate框架還是比較重的。為什么說(shuō)他重,因?yàn)樗闪颂嗟臇|西,看如下的hibernate架構(gòu)圖:

你會(huì)發(fā)現(xiàn)最上層使我們的java應(yīng)用程序的開(kāi)始,比如web的Tomcat服務(wù)器的啟動(dòng),比如main方法的啟動(dòng)等。緊接著就是需要(needing)持久化的對(duì)象,這里為什么說(shuō)是需要,而不是持久化的對(duì)象。只有保存到文件、數(shù)據(jù)庫(kù)中的數(shù)據(jù)才是持久化的。想通過(guò)hibernate,我們可以毫不費(fèi)力的將瞬時(shí)狀態(tài)的數(shù)據(jù)轉(zhuǎn)化為持久狀態(tài)的數(shù)據(jù),下面便是hibernate的內(nèi)部操作數(shù)據(jù)。其一般是這樣的流程:

我個(gè)人畫(huà)的

這個(gè)地址的圖片

如果你是用過(guò)jdbc連接數(shù)據(jù)庫(kù)的話(huà),我們一般是這樣寫(xiě)的:

package com.zby.jdbc.config;

import com.zby.util.exception.TableException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

/**
 * Created By zby on 22:12 2019/1/5
 */

public class InitJdbcFactory {

    private static Properties properties = new Properties();

    private static Logger logger = LoggerFactory.getLogger(InitJdbcFactory.class);

    static {
        try {
            //因?yàn)槭褂玫念?lèi)加載器獲取配置文件,因而,配置文件需要放在classpath下面,
            // 方能讀到數(shù)據(jù)
            properties.load(Thread.currentThread().getContextClassLoader().
                    getResourceAsStream("./jdbc.properties"));
        } catch (IOException e) {
            logger.info("初始化jdbc失敗");
            e.printStackTrace();
        }
    }

    public static Connection createConnection() {
        String drivers = properties.getProperty("jdbc.driver");
        if (StringUtils.isBlank(drivers)) {
            drivers = "com.mysql.jdbc.Driver";
        }
        String url = properties.getProperty("jdbc.url");
        String username = properties.getProperty("jdbc.username");
        String password = properties.getProperty("jdbc.password");
        try {
            Class.forName(drivers);
            return DriverManager.getConnection(url, username, password);
        } catch (ClassNotFoundException e) {
            logger.error(InitColTable.class.getName() + ":連接數(shù)據(jù)庫(kù)的找不到驅(qū)動(dòng)類(lèi)");
            throw new TableException(InitColTable.class.getName() + ": 連接數(shù)據(jù)庫(kù)的找不到驅(qū)動(dòng)類(lèi)", e);
        } catch (SQLException e) {
            logger.error(InitColTable.class.getName() + ":連接數(shù)據(jù)庫(kù)的sql異常");
            throw new TableException(InitColTable.class.getName() + "連接數(shù)據(jù)庫(kù)的sql異常", e);
        }
    }
}

hibernate一般這樣連接數(shù)據(jù)庫(kù):

public class HibernateUtils {

    private static SessionFactory sf;
    
    //靜態(tài)初始化 
    static{
    
        //【1】加載配置文件
        Configuration  conf = new Configuration().configure();
        
        //【2】 根據(jù)Configuration 配置信息創(chuàng)建 SessionFactory
        sf = conf.buildSessionFactory();
        
        //如果這里使用了hook虛擬機(jī),需要關(guān)閉hook虛擬機(jī)
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("虛擬機(jī)關(guān)閉!釋放資源");
                sf.close();
            }
        }));
        
    }
    
    /**
     * 采用openSession創(chuàng)建一個(gè)與數(shù)據(jù)庫(kù)的連接會(huì)話(huà),但這種方式需要手動(dòng)關(guān)閉與數(shù)據(jù)庫(kù)的session連接(會(huì)話(huà)),
     * 如果不關(guān)閉,則當(dāng)前session占用數(shù)據(jù)庫(kù)的資源無(wú)法釋放,最后導(dǎo)致系統(tǒng)崩潰。
     *
     **/
    public static org.hibernate.Session  openSession(){
                
        //【3】 獲得session
        Session session = sf.openSession();
        return session;
    }
    
    /**
    * 這種方式連接數(shù)據(jù)庫(kù),當(dāng)提交事務(wù)時(shí),會(huì)自動(dòng)關(guān)閉當(dāng)前會(huì)話(huà);
    * 同時(shí),創(chuàng)建session連接時(shí),autoCloseSessionEnabled和flushBeforeCompletionEnabled都為true,
    * 并且session會(huì)同sessionFactory組成一個(gè)map以sessionFactory為主鍵綁定到當(dāng)前線(xiàn)程。
    * 采用getCurrentSession()需要在Hibernate.cfg.xml配置文件中加入如下配置:
        如果是本地事務(wù),及JDBC一個(gè)數(shù)據(jù)庫(kù):
            thread
        如果是全局事務(wù),及jta事務(wù)、多個(gè)數(shù)據(jù)庫(kù)資源或事務(wù)資源:
            jta
        使用spring的getHiberanteTemplate 就不需要考慮事務(wù)管理和session關(guān)閉的問(wèn)題:
    * 
    **/
    public static org.hibernate.Session  getCurrentSession(){
        //【3】 獲得session
        Session session = sf.getCurrentSession();
        return session;
    }
}

mybatis的配置文件:

public class DBTools {
    public static SqlSessionFactory sessionFactory;
          
    static{
      try {
          //使用MyBatis提供的Resources類(lèi)加載mybatis的配置文件
          Reader reader = Resources.getResourceAsReader("mybatis.cfg.xml");
          //構(gòu)建sqlSession的工廠(chǎng)
          sessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (Exception e) {
          e.printStackTrace();
       }
     }
     
   //創(chuàng)建能執(zhí)行映射文件中sql的sqlSession
   public static SqlSession getSession(){
      return sessionFactory.openSession();
   }
}

hibernate、mybatis、jdbc創(chuàng)建于數(shù)據(jù)庫(kù)的連接方式雖然不同,但最紅都是為了將瞬時(shí)態(tài)的數(shù)據(jù)寫(xiě)入到數(shù)據(jù)庫(kù)中的,但這里主要說(shuō)的是hibernate。但是hibernate已經(jīng)封裝了這些屬性,我們可以在configuration在配置驅(qū)動(dòng)類(lèi)、用戶(hù)名、用戶(hù)密碼等。再通過(guò)sessionFactory創(chuàng)建session會(huì)話(huà),也就是加載Connection的物理連接,創(chuàng)建sql的事務(wù),然后執(zhí)行一系列的事務(wù)操作,如果事務(wù)全部成功即可成功,但凡有一個(gè)失敗都會(huì)失敗。jdbc是最基礎(chǔ)的操作,但是,萬(wàn)丈高樓平地起,只有基礎(chǔ)打牢,才能走的更遠(yuǎn)。因?yàn)閔ibernate封裝了這些基礎(chǔ),我們操作數(shù)據(jù)庫(kù)不用考慮底層如何實(shí)現(xiàn)的,因而,從某種程度上來(lái)說(shuō),hibernate還是比較重的。

hibernate為什么重(zhong)?

比如我們執(zhí)行插入語(yǔ)句,可以使用save、saveOrUpdate,merge等方法。需要將實(shí)體bean通過(guò)反射轉(zhuǎn)化為mysql的識(shí)別的SQL語(yǔ)句,同時(shí),查詢(xún)雖然用到了反射,但是最后轉(zhuǎn)化出來(lái)的還是object的根對(duì)象,這時(shí)需要將根對(duì)象轉(zhuǎn)化為當(dāng)前對(duì)象,返回給客戶(hù)端。雖然很笨重,但是文件配置好了,可以大大地提高開(kāi)發(fā)效率。畢竟現(xiàn)在的服務(wù)器的性能都比較好,公司追求的是高效率的開(kāi)發(fā),而往往不那么看重性能,除非用戶(hù)提出性能的問(wèn)題。

merge和saveOrUpdate

merge方法與saveOrUpdate從功能上類(lèi)似,但他們?nèi)杂袇^(qū)別。現(xiàn)在有這樣一種情況:我們先通過(guò)session的get方法得到一個(gè)對(duì)象u,然后關(guān)掉session,再打開(kāi)一個(gè)session并執(zhí)行saveOrUpdate(u)。此時(shí)我們可以看到拋出異常:Exception in thread "main" org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session,即在session緩存中不允許有兩個(gè)id相同的對(duì)象。不過(guò)若使用merge方法則不會(huì)異常,其實(shí)從merge的中文意思(合并)我們就可以理解了。我們重點(diǎn)說(shuō)說(shuō)merge。merge方法產(chǎn)生的效果和saveOrUpdate方法相似。這是hibernate的原碼:

    void saveOrUpdate(Object var1);

    void saveOrUpdate(String var1, Object var2);
    
    public Object merge(Object object);
    
    public Object merge(String var1, Object var2);

前者不用返回任何數(shù)據(jù),后者返回的是持久化的對(duì)象。如果根據(jù)hibernate的三種狀態(tài),比如瞬時(shí)態(tài)、持久態(tài)、游離態(tài)來(lái)說(shuō)明這個(gè)問(wèn)題,會(huì)比較難以理解,現(xiàn)在,根據(jù)參數(shù)有無(wú)id或id是否已經(jīng)存在來(lái)理解merge,而且從執(zhí)行他們兩個(gè)方法而產(chǎn)生的sql語(yǔ)句來(lái)看是一樣的。

參數(shù)實(shí)例對(duì)象沒(méi)有提供id或提供的id在數(shù)據(jù)庫(kù)找不到對(duì)應(yīng)的行數(shù)據(jù),這時(shí)merger將執(zhí)行插入操作嗎,產(chǎn)的SQL語(yǔ)句如下:

     Hibernate: select max(uid) from user     

     Hibernate: insert into hibernate1.user (name, age, uid) values (?, ?, ?)

一般情況下,我們新new一個(gè)對(duì)象,或者從前端向后端傳輸javabean序列化的對(duì)象時(shí),都不會(huì)存在當(dāng)前對(duì)象的id,如果使用merge的話(huà),就會(huì)向數(shù)據(jù)庫(kù)中插入一條數(shù)據(jù)。

參數(shù)實(shí)例對(duì)象的id在數(shù)據(jù)庫(kù)中已經(jīng)存在,此時(shí)又有兩種情況

(1)如果對(duì)象有改動(dòng),則執(zhí)行更新操作,產(chǎn)生sql語(yǔ)句有:

     Hibernate: select user0_.uid as uid0_0_, user0_.name as name0_0_, user0_.age as age0_0_ from hibernate1.user user0_ where user0_.uid=? 
     Hibernate: update hibernate1.user set name=?, age=? where uid=?

(2)如果對(duì)象未改動(dòng),則執(zhí)行查詢(xún)操作,產(chǎn)生的語(yǔ)句有:

     Hibernate: select user0_.uid as uid0_0_, user0_.name as name0_0_, user0_.age as age0_0_ from hibernate1.user user0_ where user0_.uid=?

以上三種是什么情況呢?如果我們保存用戶(hù)時(shí),數(shù)據(jù)庫(kù)中肯定不存在即將添加的用戶(hù),也就是說(shuō),我們的保存用戶(hù)就是向數(shù)據(jù)庫(kù)中添加用戶(hù)。但是,其也會(huì)跟著某些屬性, 比如說(shuō)用戶(hù)需要頭像,這是多對(duì)一的關(guān)系,一個(gè)用戶(hù)可能多個(gè)對(duì)象,然而,頭像的關(guān)聯(lián)的id不是放在用戶(hù)表中的,而是放在用戶(hù)擴(kuò)張表中的,這便用到了切分表的概念。題外話(huà),我們有時(shí)會(huì)用到快照表,比如商品快照等,也許,我們購(gòu)買(mǎi)商品時(shí),商品是一個(gè)價(jià)格,但隨后商品的價(jià)格變了,我們需要退商品時(shí),就不應(yīng)該用到商品改變后的價(jià)格了,而是商品改變前的價(jià)格。擴(kuò)展表存放用戶(hù)額外的信息,也就是用戶(hù)非必須的信息,比如說(shuō)昵稱(chēng),性別,真實(shí)姓名,頭像等。 因而,頭像是圖片類(lèi)型,使用hibernate的注解方式,創(chuàng)建用戶(hù)表、圖片表、用戶(hù)擴(kuò)展表。如下所示(部分重要信息已省略

    //用戶(hù)頭像
    @Entity
    @Table(name = "core_user")
    public class User extends BaseTenantConfObj {

         /**
         * 擴(kuò)展表
         * */
        @OneToOne(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
        private UserExt userExt;
    
    }

    //用戶(hù)擴(kuò)展表的頭像屬性
    @Entity
    @Table(name = "core_user_ext")
    public class UserExt implements Serializable {
    
        /**
         * 頭像
         */
        @ManyToOne
        @JoinColumn(name = "head_logo")
        private Picture headLogo;
    
    }
    
    //圖片表
    @Entity
    @Table(name = "core_picture")
    public class Picture extends BaseTenantObj {
    private static Logger logger = LoggerFactory.getLogger(Picture.class);

        。。。。。。
        //圖片存放在第三方的相對(duì)url。
        @Column(name = "remote_relative_url", length = 300)
        private String remoteRelativeUrl;

        //  圖片大小
        @Column(length = 8)
        private Integer size;

        /**
        * 圖片所屬類(lèi)型
        * user_logo:用戶(hù)頭像
        */
        @Column(name = "host_type", length = 58)
        private String hostType;
    
        //照片描述
        @Column(name = "description", length = 255)
        private String description;
  }
 

前端代碼是:

//這里使用到了vue.js的代碼,v-model數(shù)據(jù)的雙向綁定,前端的HTML代碼

    頭像:
    
        

推薦尺寸800*800;支持.jpg, .jpeg, .bmp, .png類(lèi)型文件,1M以?xún)?nèi)

//這里用到了js代碼,這里用到了js的屬性方法 upImg: function(me) { Utils.asyncImg({ fn: function(data) { vm.pageData.userInfo.logo = { path: data.remoteRelativeUrl, id: data.id }; } }); },

上傳頭像是異步提交,如果用戶(hù)上傳了頭像,我們?cè)谔峤挥脩?hù)信息時(shí),通過(guò)“headLogo.id”可以獲取當(dāng)前頭像的持久化的圖片對(duì)象,hibernate首先會(huì)根據(jù)屬性headLogo找到圖片表,根據(jù)當(dāng)前頭像的id找到圖片表中對(duì)應(yīng)的行數(shù)據(jù),為什么可以根據(jù)id來(lái)獲取行數(shù)據(jù)?

-圖片表的表結(jié)構(gòu)信息

從這張圖片可以看出,圖片采用默認(rèn)的存儲(chǔ)引擎,也就是InnoDB存儲(chǔ)引擎,而不是myiSam的存儲(chǔ)引擎。

innodb存儲(chǔ)引擎

我們都知道這兩種存儲(chǔ)引擎的區(qū)別,如果不知道的話(huà),可以參這篇文章MySQL中MyISAM和InnoDB的索引方式以及區(qū)別與選擇。innodb采用BTREE樹(shù)的數(shù)據(jù)結(jié)構(gòu)方式存儲(chǔ),它有0到1直接前繼和0到n個(gè)直接后繼,這是什么意思呢?一棵樹(shù)當(dāng)前葉子節(jié)點(diǎn)的直接父節(jié)點(diǎn)只有一個(gè),但其兒子節(jié)點(diǎn)可以一個(gè)都沒(méi)有,也可以有1個(gè)、2個(gè)、3個(gè)......,如果mysql采用的多對(duì)一的方式存儲(chǔ)的話(huà),你就會(huì)發(fā)現(xiàn)某條外鍵下有許多行數(shù)據(jù),比如如下的這張表

這張表記錄的是項(xiàng)目的完成情況,一般有預(yù)約階段,合同已簽,合同完成等等。你會(huì)發(fā)現(xiàn)project_id=163的行數(shù)據(jù)不止一條,我們通過(guò)查詢(xún)語(yǔ)句:SELECT zpp.* from zq_project_process zpp WHERE zpp.is_deleted = 0 AND zpp.project_id=163,查找速度非常快。為什么這么快呢,因?yàn)槲覄傞_(kāi)始說(shuō)的innodb采用的BTREE樹(shù)結(jié)構(gòu)存儲(chǔ),其數(shù)據(jù)是放在當(dāng)前索引下,什么意思?innodb的存儲(chǔ)引擎是以索引作為當(dāng)前節(jié)點(diǎn)值,比如說(shuō)銀行卡表的有個(gè)主鍵索引,備注,如果我們沒(méi)有創(chuàng)建任何索引,如果采用的innodb的數(shù)據(jù)引擎,其內(nèi)部會(huì)創(chuàng)建一個(gè)默認(rèn)的行索引,這就像我們?cè)趧?chuàng)建javabean對(duì)象時(shí),沒(méi)有創(chuàng)建構(gòu)造器,其內(nèi)部會(huì)自動(dòng)創(chuàng)建一個(gè)構(gòu)造器的道理是一樣的。其數(shù)據(jù)是怎么存儲(chǔ)的呢,如下圖所示:

mysql銀行卡數(shù)據(jù)

其內(nèi)部存儲(chǔ)數(shù)據(jù)

其所對(duì)應(yīng)的行數(shù)據(jù)是放在當(dāng)前索引下的,因而,我們?nèi)?shù)據(jù)不是取表中的數(shù)據(jù),而是取當(dāng)前主鍵索引下的數(shù)據(jù)。項(xiàng)目進(jìn)程表如同銀行卡的主鍵索引,只不過(guò)其有三個(gè)索引,分別是主鍵索引和兩個(gè)外鍵索引,如圖所示的索引:

索引名是hibernate自動(dòng)生成的一個(gè)名字,索引是項(xiàng)目id、類(lèi)型兩個(gè)索引。因?yàn)槲覀儾皇菑谋碇腥?shù)據(jù),而是從當(dāng)前索引的節(jié)點(diǎn)下取數(shù)據(jù),所以速度當(dāng)然快了。索引有主鍵索引、外鍵索引、聯(lián)合索引等,但一般情況下,主鍵索引和外鍵索引使用頻率比較高。同時(shí),innodb存儲(chǔ)引擎的支持事務(wù)操作,這是非常重要,我們操作數(shù)據(jù)庫(kù),一般都是設(shè)計(jì)事務(wù)的操作,這也mysql默認(rèn)的存儲(chǔ)引擎是innodb。

我們通過(guò)主鍵獲取圖片的行數(shù)據(jù),就像通過(guò)主鍵獲取銀行卡的行數(shù)據(jù)。這也是上面所說(shuō)的,根據(jù)是否有id來(lái)確定是插入還是更新數(shù)據(jù)。通過(guò)圖片主鍵id獲取該行數(shù)據(jù)后,hibernate會(huì)在堆中創(chuàng)建一個(gè)picture對(duì)象。用戶(hù)擴(kuò)展表的headLogo屬性指向這個(gè)圖片對(duì)象的首地址,從而創(chuàng)建一個(gè)持久化的圖片對(duì)象。前臺(tái)異步提交頭像時(shí),如果是編輯頭像,hibernate會(huì)覺(jué)擦到當(dāng)前對(duì)象的屬性發(fā)生了改變,于是,在提交事務(wù)時(shí)將修改后的游離態(tài)的類(lèi)保存到數(shù)據(jù)庫(kù)中。如果我們保存或修改用戶(hù)時(shí),我們保存的就是持久化的對(duì)象,其內(nèi)部會(huì)自動(dòng)存儲(chǔ)持久化頭像的id。這是hibernate底層所做的,我們不需要關(guān)心。

再舉一個(gè)hibernate事務(wù)提交的例子:

我們?cè)谥Ц懂?dāng)中搞得提現(xiàn)事務(wù)時(shí),調(diào)用第三方支付的SDK時(shí),第三方一般會(huì)用我們到訂單號(hào),比如我們調(diào)用連連支付這個(gè)第三方支付的SDK的payRequestBean的實(shí)體類(lèi):

/**
 * Created By zby on 11:00 2018/12/11
 * 發(fā)送到連連支付的body內(nèi)容
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PaymentRequestBean extends BaseRequestBean {


    /**
     * 版本號(hào)
     */
    @NonNull
    private String api_version;


    /**
     * 銀行賬戶(hù)
     */
    @NonNull
    private String card_no;

    /**
     * 對(duì)私
     */
    @NonNull
    private String flag_card;

    /**
     * 回調(diào)接口
     */
    @NonNull
    private String notify_url;

    /**
     * 商戶(hù)訂單號(hào)
     */
    @NonNull
    private String no_order;

    /**
     * 商戶(hù)訂單時(shí)間,時(shí)間格式為 YYYYMMddHHmmss
     */
    @NonNull
    private String dt_order;

    /**
     * 交易金額
     */
    @NonNull
    public String money_order;


    /**
     * 收款方姓名 即賬戶(hù)名
     */
    @NonNull
    private String acct_name;

    /**
     * 收款銀行姓名
     */
    private String bank_name;

    /**
     * 訂單描述  ,代幣類(lèi)型 + 支付
     */
    @NonNull
    private String info_order;

    /**
     * 收款備注
     */
    private String memo;

    /**
     * 支行名稱(chēng)
     */
    private String brabank_name;


}

商戶(hù)訂單號(hào)是必傳的,且這個(gè)訂單號(hào)是我們這邊提供的,這就有一個(gè)問(wèn)題了,怎么避免訂單號(hào)不重復(fù)呢?我們可以在提現(xiàn)記錄表事先存儲(chǔ)一個(gè)訂單號(hào),訂單號(hào)的規(guī)則如下:"WD" +系統(tǒng)時(shí)間+ 當(dāng)前提現(xiàn)記錄的id,這個(gè)id怎么拿到呢?既然底層使用的是merge方法,我們事先不創(chuàng)建訂單號(hào),先保存這個(gè)記錄,其返回的是已經(jīng)創(chuàng)建好的持久化的對(duì)象,該持久化的對(duì)象肯定有提現(xiàn)主鍵的id。我們拿到該持久化對(duì)象的主鍵id,便可以封裝訂單號(hào),再次保存這個(gè)持久化的對(duì)象,其內(nèi)部會(huì)執(zhí)行類(lèi)似以下的操作:

Hibernate: select user0_.uid as uid0_0_, user0_.name as name0_0_, user0_.age as age0_0_ 
from hibernate1.user user0_ where user0_.uid=? 
Hibernate: update hibernate1.user set name=?, age=? where uid=?

代碼如下:

 withdraw.setWithdrawStatus(WITHDRAW_STATUS_WAIT_PAY);
 withdraw.setApplyTime(currentTime);
 withdraw.setExchangeHasThisMember(hasThisMember ? YES : NO);
 withdraw = withdrawDao.save(withdraw);
 withdraw.setOrderNo("WD" + DateUtil.ISO_DATETIME_FORMAT_NONE.format(currentTime) + withdraw.getId());
 withdrawDao.save(withdraw);

不管哪種情況,merge的返回值都是一個(gè)持久化的實(shí)例對(duì)象,但對(duì)于參數(shù)而言不會(huì)改變它的狀態(tài)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/73170.html

相關(guān)文章

  • Hibernate配置及自定義注冊(cè)映射文件

    摘要:一配置屬性詳解可以在各式各樣不同環(huán)境下工作而設(shè)計(jì)的因此存在著大量的配置參數(shù)。以簡(jiǎn)便操作,多數(shù)配置參數(shù)都有默認(rèn)的配置值也是我們?nèi)粘J褂玫谋仨毱贰? Hibernate (開(kāi)放源代碼的對(duì)象關(guān)系映射框架) Hibernate是一個(gè)開(kāi)放源代碼的對(duì)象關(guān)系映射框架,它對(duì)JDBC進(jìn)行了非常輕量級(jí)的對(duì)象封裝, 它將POJO與數(shù)據(jù)庫(kù)表建立映射關(guān)系,是一個(gè)全自動(dòng)的orm框架,hibernat...

    coordinate35 評(píng)論0 收藏0
  • 幾個(gè)數(shù)據(jù)持久化框架Hibernate、JPA、Mybatis、JOOQJDBC Template

    摘要:不管是還是,表之間的連接查詢(xún),被映射為實(shí)體類(lèi)之間的關(guān)聯(lián)關(guān)系,這樣,如果兩個(gè)實(shí)體類(lèi)之間沒(méi)有實(shí)現(xiàn)關(guān)聯(lián)關(guān)系,你就不能把兩個(gè)實(shí)體或者表起來(lái)查詢(xún)。 因?yàn)轫?xiàng)目需要選擇數(shù)據(jù)持久化框架,看了一下主要幾個(gè)流行的和不流行的框架,對(duì)于復(fù)雜業(yè)務(wù)系統(tǒng),最終的結(jié)論是,JOOQ是總體上最好的,可惜不是完全免費(fèi),最終選擇JDBC Template。 Hibernate和Mybatis是使用最多的兩個(gè)主流框架,而JOO...

    xietao3 評(píng)論0 收藏0
  • Hibernate入門(mén)指南

    摘要:在使用作為應(yīng)用時(shí)推薦使用作為開(kāi)發(fā)工具導(dǎo)入相應(yīng)的的包到文件下的目錄下關(guān)于開(kāi)發(fā)中導(dǎo)入的說(shuō)明在此提供一個(gè)包下載鏈接,地址百度云盤(pán)下載好以后解壓到某個(gè)文件夾里解壓好以后,開(kāi)發(fā)所需要的包在解壓后的包下,將該文件夾下的包復(fù)制到項(xiàng)目中另外還需 1.在使用Hibernate作為orm應(yīng)用時(shí)推薦使用myeclipse作為開(kāi)發(fā)工具2.導(dǎo)入相應(yīng)的Hibernate的jar包到webroot文件下的lib目錄...

    Codeing_ls 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

includecmath

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<