最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

tomcat的keepAlive參數(shù)深入探究

 更新時間:2023年11月27日 11:20:20   作者:codecraft  
這篇文章主要為大家介紹了tomcat的keepAlive參數(shù)深入探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

本文主要研究一下tomcat的keepAlive參數(shù)

maxKeepAliveRequests

org/apache/tomcat/util/net/AbstractEndpoint.java

/**
     * Max keep alive requests
     */
    private int maxKeepAliveRequests=100; // as in Apache HTTPD server
    public int getMaxKeepAliveRequests() {
        // Disable keep-alive if the server socket is not bound
        if (bindState.isBound()) {
            return maxKeepAliveRequests;
        } else {
            return 1;
        }
    }
    public void setMaxKeepAliveRequests(int maxKeepAliveRequests) {
        this.maxKeepAliveRequests = maxKeepAliveRequests;
    }
AbstractEndpoint定義了maxKeepAliveRequests屬性,默認為100

Http11Processor

org/apache/coyote/http11/Http11Processor.java

public class Http11Processor extends AbstractProcessor {
    private static final Log log = LogFactory.getLog(Http11Processor.class);
    public SocketState service(SocketWrapperBase<?> socketWrapper)
        throws IOException {
        RequestInfo rp = request.getRequestProcessor();
        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
        // Setting up the I/O
        setSocketWrapper(socketWrapper);
        // Flags
        keepAlive = true;
        openSocket = false;
        readComplete = true;
        boolean keptAlive = false;
        SendfileState sendfileState = SendfileState.DONE;
        //......
        while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&
                sendfileState == SendfileState.DONE && !protocol.isPaused()) {
            //......
            int maxKeepAliveRequests = protocol.getMaxKeepAliveRequests();
            if (maxKeepAliveRequests == 1) {
                keepAlive = false;
            } else if (maxKeepAliveRequests > 0 &&
                    socketWrapper.decrementKeepAlive() <= 0) {
                keepAlive = false;
            }   
            //......
            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
            sendfileState = processSendfile(socketWrapper);            
        }         
    }        
}
Http11Processor的service方法會從protocol獲取maxKeepAliveRequests,若為1則重置keepAlive為false,若大于0則執(zhí)行socketWrapper.decrementKeepAlive(),若小于等于0則重置keepAlive為false,跳出循環(huán),requestInfo的stage不是STAGE_KEEPALIVE

decrementKeepAlive

org/apache/tomcat/util/net/SocketWrapperBase.java

public abstract class SocketWrapperBase<E> {
    private static final Log log = LogFactory.getLog(SocketWrapperBase.class);
    protected static final StringManager sm = StringManager.getManager(SocketWrapperBase.class);
    private E socket;
    private final AbstractEndpoint<E,?> endpoint;
    protected final AtomicBoolean closed = new AtomicBoolean(false);
    // Volatile because I/O and setting the timeout values occurs on a different
    // thread to the thread checking the timeout.
    private volatile long readTimeout = -1;
    private volatile long writeTimeout = -1;
    private volatile int keepAliveLeft = 100;
    //......
    public void setKeepAliveLeft(int keepAliveLeft) { this.keepAliveLeft = keepAliveLeft; }
    public int decrementKeepAlive() { return (--keepAliveLeft); }
}
SocketWrapperBase定義了keepAliveLeft屬性,默認為100,它提供了setKeepAliveLeft方法以及decrementKeepAlive方法

prepareResponse

org/apache/coyote/http11/Http11Processor.java

protected final void prepareResponse() throws IOException {
        boolean entityBody = true;
        contentDelimitation = false;
        OutputFilter[] outputFilters = outputBuffer.getFilters();
        if (http09 == true) {
            // HTTP/0.9
            outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
            outputBuffer.commit();
            return;
        }
        //......
        // If we know that the request is bad this early, add the
        // Connection: close header.
        if (keepAlive && statusDropsConnection(statusCode)) {
            keepAlive = false;
        }
        if (!keepAlive) {
            // Avoid adding the close header twice
            if (!connectionClosePresent) {
                headers.addValue(Constants.CONNECTION).setString(
                        Constants.CLOSE);
            }
        } else if (!getErrorState().isError()) {
            if (!http11) {
                headers.addValue(Constants.CONNECTION).setString(Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN);
            }
            if (protocol.getUseKeepAliveResponseHeader()) {
                boolean connectionKeepAlivePresent =
                    isConnectionToken(request.getMimeHeaders(), Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN);
                if (connectionKeepAlivePresent) {
                    int keepAliveTimeout = protocol.getKeepAliveTimeout();
                    if (keepAliveTimeout > 0) {
                        String value = "timeout=" + keepAliveTimeout / 1000L;
                        headers.setValue(Constants.KEEP_ALIVE_HEADER_NAME).setString(value);
                        if (http11) {
                            // Append if there is already a Connection header,
                            // else create the header
                            MessageBytes connectionHeaderValue = headers.getValue(Constants.CONNECTION);
                            if (connectionHeaderValue == null) {
                                headers.addValue(Constants.CONNECTION).setString(Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN);
                            } else {
                                connectionHeaderValue.setString(
                                        connectionHeaderValue.getString() + ", " + Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN);
                            }
                        }
                    }
                }
            }
        }
        //......        
    }    
    /**
     * Determine if we must drop the connection because of the HTTP status
     * code.  Use the same list of codes as Apache/httpd.
     */
    private static boolean statusDropsConnection(int status) {
        return status == 400 /* SC_BAD_REQUEST */ ||
               status == 408 /* SC_REQUEST_TIMEOUT */ ||
               status == 411 /* SC_LENGTH_REQUIRED */ ||
               status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ ||
               status == 414 /* SC_REQUEST_URI_TOO_LONG */ ||
               status == 500 /* SC_INTERNAL_SERVER_ERROR */ ||
               status == 503 /* SC_SERVICE_UNAVAILABLE */ ||
               status == 501 /* SC_NOT_IMPLEMENTED */;
    }
Http11Processor的prepareResponse方法在statusDropsConnection時會設(shè)置keepalive為false,對于為false的會判斷是否已經(jīng)有Connection: close的header,如果沒有則給添加上

keepAliveTimeout

org/apache/tomcat/util/net/AbstractEndpoint.java

public abstract class AbstractEndpoint<S,U> {
    //......
    /**
     * Keepalive timeout, if not set the soTimeout is used.
     */
    private Integer keepAliveTimeout = null;
    public int getKeepAliveTimeout() {
        if (keepAliveTimeout == null) {
            return getConnectionTimeout();
        } else {
            return keepAliveTimeout.intValue();
        }
    }
    public void setKeepAliveTimeout(int keepAliveTimeout) {
        this.keepAliveTimeout = Integer.valueOf(keepAliveTimeout);
    }
    /**
     * Socket timeout.
     *
     * @return The current socket timeout for sockets created by this endpoint
     */
    public int getConnectionTimeout() { return socketProperties.getSoTimeout(); }
    public void setConnectionTimeout(int soTimeout) { socketProperties.setSoTimeout(soTimeout); }
    //......
}
AbstractEndpoint定義了keepAliveTimeout熟悉,默認為null取的是socketProperties.getSoTimeout()的值

protocol.getKeepAliveTimeout()

org/apache/coyote/http11/Http11Processor.java

public SocketState service(SocketWrapperBase<?> socketWrapper)
        throws IOException {
        RequestInfo rp = request.getRequestProcessor();
        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);

        // Setting up the I/O
        setSocketWrapper(socketWrapper);

        // Flags
        keepAlive = true;
        openSocket = false;
        readComplete = true;
        boolean keptAlive = false;
        SendfileState sendfileState = SendfileState.DONE;

        while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&
                sendfileState == SendfileState.DONE && !protocol.isPaused()) {

            // Parsing the request header
            try {
                if (!inputBuffer.parseRequestLine(keptAlive, protocol.getConnectionTimeout(),
                        protocol.getKeepAliveTimeout())) {
                    if (inputBuffer.getParsingRequestLinePhase() == -1) {
                        return SocketState.UPGRADING;
                    } else if (handleIncompleteRequestLineRead()) {
                        break;
                    }
                }
            }
            
            //......
        }
    }
Http11Processor的service方法在keepalive為true時會執(zhí)行inputBuffer.parseRequestLine(keptAlive, protocol.getConnectionTimeout(),protocol.getKeepAliveTimeout())

parseRequestLine

org/apache/coyote/http11/Http11InputBuffer.java

    /**
     * Read the request line. This function is meant to be used during the
     * HTTP request header parsing. Do NOT attempt to read the request body
     * using it.
     *
     * @throws IOException If an exception occurs during the underlying socket
     * read operations, or if the given buffer is not big enough to accommodate
     * the whole line.
     *
     * @return true if data is properly fed; false if no data is available
     * immediately and thread should be freed
     */
    boolean parseRequestLine(boolean keptAlive, int connectionTimeout, int keepAliveTimeout)
            throws IOException {
        // check state
        if (!parsingRequestLine) {
            return true;
        }
        //
        // Skipping blank lines
        //
        if (parsingRequestLinePhase < 2) {
            do {
                // Read new bytes if needed
                if (byteBuffer.position() >= byteBuffer.limit()) {
                    if (keptAlive) {
                        // Haven't read any request data yet so use the keep-alive
                        // timeout.
                        wrapper.setReadTimeout(keepAliveTimeout);
                    }
                    if (!fill(false)) {
                        // A read is pending, so no longer in initial state
                        parsingRequestLinePhase = 1;
                        return false;
                    }
                    // At least one byte of the request has been received.
                    // Switch to the socket timeout.
                    wrapper.setReadTimeout(connectionTimeout);
                }
                if (!keptAlive && byteBuffer.position() == 0 && byteBuffer.limit() >= CLIENT_PREFACE_START.length - 1) {
                    boolean prefaceMatch = true;
                    for (int i = 0; i < CLIENT_PREFACE_START.length && prefaceMatch; i++) {
                        if (CLIENT_PREFACE_START[i] != byteBuffer.get(i)) {
                            prefaceMatch = false;
                        }
                    }
                    if (prefaceMatch) {
                        // HTTP/2 preface matched
                        parsingRequestLinePhase = -1;
                        return false;
                    }
                }
                // Set the start time once we start reading data (even if it is
                // just skipping blank lines)
                if (request.getStartTime() < 0) {
                    request.setStartTime(System.currentTimeMillis());
                }
                chr = byteBuffer.get();
            } while ((chr == Constants.CR) || (chr == Constants.LF));
            byteBuffer.position(byteBuffer.position() - 1);
            parsingRequestLineStart = byteBuffer.position();
            parsingRequestLinePhase = 2;
        }
        if (parsingRequestLinePhase == 2) {
            //
            // Reading the method name
            // Method name is a token
            //
            boolean space = false;
            while (!space) {
                // Read new bytes if needed
                if (byteBuffer.position() >= byteBuffer.limit()) {
                    if (!fill(false)) // request line parsing
                        return false;
                }
                // Spec says method name is a token followed by a single SP but
                // also be tolerant of multiple SP and/or HT.
                int pos = byteBuffer.position();
                chr = byteBuffer.get();
                if (chr == Constants.SP || chr == Constants.HT) {
                    space = true;
                    request.method().setBytes(byteBuffer.array(), parsingRequestLineStart,
                            pos - parsingRequestLineStart);
                } else if (!HttpParser.isToken(chr)) {
                    // Avoid unknown protocol triggering an additional error
                    request.protocol().setString(Constants.HTTP_11);
                    String invalidMethodValue = parseInvalid(parsingRequestLineStart, byteBuffer);
                    throw new IllegalArgumentException(sm.getString("iib.invalidmethod", invalidMethodValue));
                }
            }
            parsingRequestLinePhase = 3;
        }
        if (parsingRequestLinePhase == 3) {
            // Spec says single SP but also be tolerant of multiple SP and/or HT
            boolean space = true;
            while (space) {
                // Read new bytes if needed
                if (byteBuffer.position() >= byteBuffer.limit()) {
                    if (!fill(false)) // request line parsing
                        return false;
                }
                chr = byteBuffer.get();
                if (!(chr == Constants.SP || chr == Constants.HT)) {
                    space = false;
                    byteBuffer.position(byteBuffer.position() - 1);
                }
            }
            parsingRequestLineStart = byteBuffer.position();
            parsingRequestLinePhase = 4;
        }
        if (parsingRequestLinePhase == 4) {
            // Mark the current buffer position
            int end = 0;
            //
            // Reading the URI
            //
            boolean space = false;
            while (!space) {
                // Read new bytes if needed
                if (byteBuffer.position() >= byteBuffer.limit()) {
                    if (!fill(false)) // request line parsing
                        return false;
                }
                int pos = byteBuffer.position();
                prevChr = chr;
                chr = byteBuffer.get();
                if (prevChr == Constants.CR && chr != Constants.LF) {
                    // CR not followed by LF so not an HTTP/0.9 request and
                    // therefore invalid. Trigger error handling.
                    // Avoid unknown protocol triggering an additional error
                    request.protocol().setString(Constants.HTTP_11);
                    String invalidRequestTarget = parseInvalid(parsingRequestLineStart, byteBuffer);
                    throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget", invalidRequestTarget));
                }
                if (chr == Constants.SP || chr == Constants.HT) {
                    space = true;
                    end = pos;
                } else if (chr == Constants.CR) {
                    // HTTP/0.9 style request. CR is optional. LF is not.
                } else if (chr == Constants.LF) {
                    // HTTP/0.9 style request
                    // Stop this processing loop
                    space = true;
                    // Set blank protocol (indicates HTTP/0.9)
                    request.protocol().setString("");
                    // Skip the protocol processing
                    parsingRequestLinePhase = 7;
                    if (prevChr == Constants.CR) {
                        end = pos - 1;
                    } else {
                        end = pos;
                    }
                } else if (chr == Constants.QUESTION && parsingRequestLineQPos == -1) {
                    parsingRequestLineQPos = pos;
                } else if (parsingRequestLineQPos != -1 && !httpParser.isQueryRelaxed(chr)) {
                    // Avoid unknown protocol triggering an additional error
                    request.protocol().setString(Constants.HTTP_11);
                    // %nn decoding will be checked at the point of decoding
                    String invalidRequestTarget = parseInvalid(parsingRequestLineStart, byteBuffer);
                    throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget", invalidRequestTarget));
                } else if (httpParser.isNotRequestTargetRelaxed(chr)) {
                    // Avoid unknown protocol triggering an additional error
                    request.protocol().setString(Constants.HTTP_11);
                    // This is a general check that aims to catch problems early
                    // Detailed checking of each part of the request target will
                    // happen in Http11Processor#prepareRequest()
                    String invalidRequestTarget = parseInvalid(parsingRequestLineStart, byteBuffer);
                    throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget", invalidRequestTarget));
                }
            }
            if (parsingRequestLineQPos >= 0) {
                request.queryString().setBytes(byteBuffer.array(), parsingRequestLineQPos + 1,
                        end - parsingRequestLineQPos - 1);
                request.requestURI().setBytes(byteBuffer.array(), parsingRequestLineStart,
                        parsingRequestLineQPos - parsingRequestLineStart);
            } else {
                request.requestURI().setBytes(byteBuffer.array(), parsingRequestLineStart,
                        end - parsingRequestLineStart);
            }
            // HTTP/0.9 processing jumps to stage 7.
            // Don't want to overwrite that here.
            if (parsingRequestLinePhase == 4) {
                parsingRequestLinePhase = 5;
            }
        }
        if (parsingRequestLinePhase == 5) {
            // Spec says single SP but also be tolerant of multiple and/or HT
            boolean space = true;
            while (space) {
                // Read new bytes if needed
                if (byteBuffer.position() >= byteBuffer.limit()) {
                    if (!fill(false)) // request line parsing
                        return false;
                }
                byte chr = byteBuffer.get();
                if (!(chr == Constants.SP || chr == Constants.HT)) {
                    space = false;
                    byteBuffer.position(byteBuffer.position() - 1);
                }
            }
            parsingRequestLineStart = byteBuffer.position();
            parsingRequestLinePhase = 6;
            // Mark the current buffer position
            end = 0;
        }
        if (parsingRequestLinePhase == 6) {
            //
            // Reading the protocol
            // Protocol is always "HTTP/" DIGIT "." DIGIT
            //
            while (!parsingRequestLineEol) {
                // Read new bytes if needed
                if (byteBuffer.position() >= byteBuffer.limit()) {
                    if (!fill(false)) // request line parsing
                        return false;
                }
                int pos = byteBuffer.position();
                prevChr = chr;
                chr = byteBuffer.get();
                if (chr == Constants.CR) {
                    // Possible end of request line. Need LF next.
                } else if (prevChr == Constants.CR && chr == Constants.LF) {
                    end = pos - 1;
                    parsingRequestLineEol = true;
                } else if (!HttpParser.isHttpProtocol(chr)) {
                    String invalidProtocol = parseInvalid(parsingRequestLineStart, byteBuffer);
                    throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol", invalidProtocol));
                }
            }
            if ((end - parsingRequestLineStart) > 0) {
                request.protocol().setBytes(byteBuffer.array(), parsingRequestLineStart,
                        end - parsingRequestLineStart);
                parsingRequestLinePhase = 7;
            }
            // If no protocol is found, the ISE below will be triggered.
        }
        if (parsingRequestLinePhase == 7) {
            // Parsing is complete. Return and clean-up.
            parsingRequestLine = false;
            parsingRequestLinePhase = 0;
            parsingRequestLineEol = false;
            parsingRequestLineStart = 0;
            return true;
        }
        throw new IllegalStateException(sm.getString("iib.invalidPhase", Integer.valueOf(parsingRequestLinePhase)));
    }
Http11InputBuffer的parseRequestLine方法對于讀不到請求數(shù)據(jù)時會設(shè)置SocketWrapperBase的readTimeout為keepAliveTimeout

小結(jié)

tomcat提供了maxKeepAliveRequests及keepAliveTimeout兩個keepalive相關(guān)的參數(shù),其中在SocketWrapperBase維護了keepAliveLeft及readTimeout屬性,Http11Processor的service方法會在protocol的maxKeepAliveRequests大于0則執(zhí)行socketWrapper.decrementKeepAlive(),若小于等于0則重置keepAlive為false;Http11Processor的prepareResponse方法在statusDropsConnection時會設(shè)置keepalive為false,對于為false的會判斷是否已經(jīng)有Connection: close的header,如果沒有則給添加上。

Http11Processor的service方法在keepalive為true時會執(zhí)行inputBuffer.parseRequestLine,對于讀不到請求數(shù)據(jù)時會設(shè)置SocketWrapperBase的readTimeout為keepAliveTimeout(默認為null取的是socketProperties.getSoTimeout()的值)。

以上就是tomcat的keepAlive參數(shù)深入探究的詳細內(nèi)容,更多關(guān)于tomcat keepAlive參數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java實現(xiàn)FutureTask的示例詳解

    Java實現(xiàn)FutureTask的示例詳解

    在并發(fā)編程當(dāng)中我們最常見的需求就是啟動一個線程執(zhí)行一個函數(shù)去完成我們的需求,而在這種需求當(dāng)中,我們需要函數(shù)有返回值。Java給我們提供了這種機制,去實現(xiàn)這一個效果:FutureTask。本文為大家準備了Java實現(xiàn)FutureTask的示例代碼,需要的可以參考一下
    2022-08-08
  • Mybatis-Plus select不列出全部字段的方法

    Mybatis-Plus select不列出全部字段的方法

    這篇文章主要介紹了Mybatis-Plus select不列出全部字段的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Java服務(wù)器主機信息監(jiān)控工具類的示例代碼

    Java服務(wù)器主機信息監(jiān)控工具類的示例代碼

    這篇文章主要介紹了Java服務(wù)器主機信息監(jiān)控工具類的示例代碼,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • 詳解Java實踐之抽象工廠模式

    詳解Java實踐之抽象工廠模式

    抽象工廠模式用于產(chǎn)品族的構(gòu)建。抽象工廠是所有形態(tài)的工廠模式中最為抽象和最具一般性的一種形態(tài)。抽象工廠是指當(dāng)有多個抽象角色時使用的一種工廠模式。抽象工廠模式可以向客戶端提供一個接口,使客戶端在不必指定產(chǎn)品的具體情況下,創(chuàng)建多個產(chǎn)品族中的產(chǎn)品對象
    2021-06-06
  • SpringBoot中注解實現(xiàn)定時任務(wù)的兩種方式

    SpringBoot中注解實現(xiàn)定時任務(wù)的兩種方式

    這篇文章主要介紹了SpringBoot中注解實現(xiàn)定時任務(wù)的兩種方式,SpringBoot 定時任務(wù)是一種在SpringBoot應(yīng)用中自動執(zhí)行任務(wù)的機制,通過使用Spring框架提供的@Scheduled注解,我們可以輕松地創(chuàng)建定時任務(wù),需要的朋友可以參考下
    2023-10-10
  • Spring底層原理深入分析

    Spring底層原理深入分析

    Spring框架是一個開放源代碼的J2EE應(yīng)用程序框架,由Rod Johnson發(fā)起,是針對bean的生命周期進行管理的輕量級容器(lightweight container)。 Spring解決了開發(fā)者在J2EE開發(fā)中遇到的許多常見的問題,提供了功能強大IOC、AOP及Web MVC等功能
    2022-07-07
  • Java實現(xiàn)DBF文件讀寫操作的完整指南

    Java實現(xiàn)DBF文件讀寫操作的完整指南

    DBF是一種數(shù)據(jù)庫文件格式,主要存儲結(jié)構(gòu)化數(shù)據(jù),本文將詳細介紹如何在Java中使用JDBF庫來讀取和創(chuàng)建DBF文件,有需要的小伙伴可以參考一下
    2025-04-04
  • SpringBoot實現(xiàn)Md5對數(shù)據(jù)庫數(shù)據(jù)加密的示例

    SpringBoot實現(xiàn)Md5對數(shù)據(jù)庫數(shù)據(jù)加密的示例

    本文主要介紹了SpringBoot實現(xiàn)Md5對數(shù)據(jù)庫數(shù)據(jù)加密的示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Java使用@Retryable注解實現(xiàn)HTTP請求重試

    Java使用@Retryable注解實現(xiàn)HTTP請求重試

    HTTP調(diào)用是Java應(yīng)用與外部API進行交互時重要的訪問方式之一,為了確保在遇到臨時性問題時能自動重試,我們可以設(shè)計一個靈活的重試機制,在Java中,我們可以通過注解來實現(xiàn)這一功能,文將介紹如何使用注解@Retryable來實現(xiàn)HTTP調(diào)用的重試機制,需要的朋友可以參考下
    2024-10-10
  • hibernate屬性級別注解實例代碼

    hibernate屬性級別注解實例代碼

    這篇文章主要介紹了hibernate屬性級別注解實例代碼,涉及屬性級別注釋添加方式及種類,具有一定參考價值,需要的朋友可以了解下。
    2017-10-10

最新評論

怀安县| 恩平市| 灵石县| 舟曲县| 郎溪县| 临清市| 安国市| 罗平县| 霍城县| 千阳县| 丰城市| 西丰县| 吴旗县| 新绛县| 东源县| 温泉县| 璧山县| 乐昌市| 石渠县| 河西区| 北海市| 永胜县| 镇宁| 五大连池市| 宜春市| 泰来县| 蚌埠市| 天等县| 齐河县| 合江县| 莆田市| 额敏县| 延吉市| 新晃| 怀集县| 教育| 定边县| 遂溪县| 建昌县| 连平县| 惠州市|