<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Leo's Blog

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      13 隨筆 :: 3 文章 :: 18 評論 :: 0 Trackbacks

    2006年5月8日 #

    ??? 昨天讀了一篇關于JDBC4.0設計與性能提高的文章,由于小弟英語翻譯水準實在有限,就不在這里獻丑了,就把原文給大家轉載出來供大家閱讀:

    轉載自:http://www.javaworld.com/javaworld/jw-05-2006/jw- 0501-jdbc .html

    Design and performance improvements with JDBC 4.0

    Effectively utilize JDBC'S features to get desired results with less code

    Summary
    Java Database Connectivity (JDBC) 4.0 is ready for release by mid 2006 as a part of Java Standard Edition 6.0. How can you leverage the new specification to improve the design and performance of database access and interactions in Java applications? This article discusses the new features of JDBC 4.0, illustrates its solutions to some existing problems, and presents its improvements in design and performance through examples. (2,100 words; May 1, 2006)
    By Shashank Tiwari


    Java Database Connectivity (JDBC), which has existed from the first public version of the core Java language, has evolved significantly over the last 10 years. In its current version, 4.0, which will be packaged with Java Standard Edition 6.0 (Java SE is Sun's new name for J2SE), it shows significant improvements in design and provides a richer API, with focus on ease of development and improvement in productivity.

    This article discusses some of the important changes in the JDBC specification that either improve the design or facilitate better performance. The article does not enlist or survey every single change incorporated as a part of Java Specification Request 221, the JDBC 4.0 initiative.

    After reading this article, you should be ready to leverage the new features in your next set of applications.

    Annotations and the generic DataSet
    I assume you are already aware of annotations and generics, which were introduced in Java with J2SE 5.0. JDBC 4.0 introduces annotations and the generic DataSet. This change aims to simplify execution of SQL queries (in scenarios that return a single result set) and SQL DML (data manipulation language) statements (that return either a row count or nothing).

    The new API defines a set of Query and DataSet interfaces. The Query interface defines a set of methods decorated with the JDBC annotations. These decorated methods describe the SQL select and update statements, and specify how the result set should be bound to a DataSet. The DataSet interface is a parameterized type, as defined by generics. The DataSet interface provides a type-safe definition for the result set data.

    All Query interfaces inherit from the BaseQuery interface. A concrete implementation of the interface can be instantiated using either the Connection.createQueryObject() or DataSource.createQueryObject() methods and passing a Query interface type as its parameter.

    A DataSet interface inherits from java.util.List. A data class describing the columns of the result set data, returned by an annotated method of the Query interface, is its parameter type. A DataSet can be manipulated and operated upon both in a connected and disconnected mode. Thus, the DataSet is implemented either as a ResultSet or a CachedRowSet, depending on its operating mode: connected or disconnected. DataSet, being a sub-interface of the java.util.List, allows access of its data rows with the Iterator pattern, using the java.util.Iterator interface.

    The data class or the user-defined class, which is a parameter type of the DataSet interface, can be specified in two ways: as a structure or as a JavaBeans object. Either method achieves the goal of binding result set data columns to user-defined class definitions, but the JavaBeans component model is more elegant and facilitates object definition reuse within other frameworks that support the JavaBeans model.

    Listing 1 illustrates code snippets for a simple example to show how the new API is used to create and run SQL queries, define result set data using a user-defined class, and bind the returned result set to the user-defined specifications.

    Listing 1. Employee user-defined type and employeeQueries

    pubic class Employee {
    ?? private int employeeId;
    ?? private String firstName;
    ?? private String lastName;

    ?? public int getEmployeeId() {
    ??????return employeeId;
    ?? }
    ??
    ?? public setEmployeeId(int employeeId) {
    ??????this.employeeId = employeeId;
    ?? }

    ?? public String getFirstName() {
    ??????return firstName;
    ?? }

    ?? public setFirstName(String firstName) {
    ??????this.firstName = firstName;
    ?? }

    ?? pubic String lastName() {
    ??????return lastName;
    ?? }

    ?? public setLastName(String lastName) {
    ??????this.lastName = lastName;
    ?? }
    }


    interface EmployeeQueries extends BaseQuery {
    ?? @Select (sql="SELECT employeeId, firstName, lastName FROM employee")
    ?? DataSet<Employee> getAllEmployees ();

    ?? @Update (sql="delete from employee")
    ?? int deleteAllEmployees ();
    }


    Connection con = ...

    EmployeeQueries empQueries = con.createQueryObject (EmployeeQueries.class);

    DataSet<Employee> empData = empQueries.getAllEmployees ();

    Exception-handling enhancements
    The exception-handling functionality in the JDBC API prior to version 4.0 is limited and often insufficient. SQLException is thrown for all types of errors. There is no classification of exceptions, and no hierarchy defines them. The only way to get some meaningful information is to retrieve and analyze the SQLState value. SQLState values and their corresponding meanings change from datasource to datasource; hence, getting to the root of the problem and efficiently handling exceptions proves to be a tedious task.

    JDBC 4.0 has enhanced exception-handling capability and alleviates some of the mentioned problems. The key changes are as follows:

    • Classification of SQLException into transient and non-transient types
    • Support for chained exceptions
    • Implementation of the Iterable interface

    The SQLTransientException is thrown where a previously failed operation may succeed on retrial. The SQLNonTransientException is thrown where retrial will not lead to a successful operation unless the cause of the SQLException is corrected.

    Figure 1 illustrates the subclasses of SQLTransientException and SQLNonTransientException.


    Figure 1. SQL exception classes: Transient and non-transient

    Support for chained exceptions are now included. New constructors add extra parameters to capture possible causes for the exception. Multiple SQLExceptions could be iterated over in a loop, and getCause() could be called to determine the exception's possible cause. The getCause() method can return non-SQLExceptions if they are the underlying cause of the exceptions.

    The SQLException class now implements the Iterable interface and supports the J2SE 5.0 for each loop for easier and more elegant looping.

    Listing 2 depicts the usage of the new for-each-loop construct:

    Listing 2. For each loop

    catch(SQLException ex) {
    ?? for(Throwable t : ex) {
    ??????System.out.println("exception:" + t);
    ?? }
    }


    SQL/XML
    A large amount of data now exists in the XML format. Databases have extended support for the XML data type by defining a standard XML type in the SQL 2003 specification. Most database vendors have an implementation of the XML data type in their new releases. With the inclusion of such a type, an XML dataset or document could be one of the fields or column values in a row of a database table. Prior to JDBC 4.0, perhaps the best way to manipulate such data within the JDBC framework is to use proprietary extensions from the driver vendors or access it as a CLOB type.

    JDBC 4.0 now defines SQLXML as the Java data type that maps the database SQL XML type. The API supports processing of an XML type as a string or as a StAX stream. Streaming API for XML, which for Java has been adopted via JSR 173, is based on the Iterator pattern, as opposed to the Simple API for XML Processing (SAX), which is based on the Observer pattern.

    Invoking the Connection object's createSQLXML() method can create a SQLXML object. This is an empty object, so the data can be attached to it by either using the setString() method or by associating an XML stream using the createXMLStreamWriter() method with the object. Similarly, XML data can be retrieved from a SQLXML object using getString() or associating an XML stream using createXMLStreamReader() with the object.

    The ResultSet, the PreparedStatement, and the CallableStatement interfaces have getSQLXML() methods for retrieving a SQLXML data type. PreparedStatement and CallableStatement also have setSQLXML() methods to add SQLXML objects as parameters.

    The SQLXML resources can be released by calling their free() methods, which might prove pertinent where the objects are valid in long-running transactions. DatabaseMetaData's getTypeInfo() method can be called on a datasource to check if the database supports the SQLXML data type, since this method returns all the data types it supports.

    Connections and Statements
    The Connection interface definitions have been enhanced to analyze connection state and usage to facilitate efficiency.

    Sometimes database connections are unusable though they may not necessarily be closed and garbage collected. In such situations, the database appears slow and unresponsive. In most of these circumstances, reinitializing the connections is perhaps the only way to resolve the problem. When using the JDBC API prior to version 4.0, there is no way to distinguish between a stale connection and a closed connection. The new API adds an isValid() method to the Connection interface to query if the connection is still valid.

    Also, database connections are often shared among clients, and sometimes some clients tend to use more resources than others, which can lead to starvation-like situations. The Connection interface defines a setClientInfo() method to define client-specific properties, which could be utilized to analyze and monitor resource utilization by the clients.

    RowId
    The RowId in many databases is a unique way to identify a row in a table. Queries using RowId in the search criteria are often the fastest way to retrieve data, especially true in the case of the Oracle and DB2 databases. Since java.sql.RowId is now a built-in type in Java, you could utilize the performance benefits associated with its usage. RowIds are most useful in identifying unique and specific rows when duplicate data exists and some rows are identical. However, it is important to understand that RowIds often are unique only for a table and not for the entire database; they may change and are not supported by all databases. RowIds are typically not portable across datasources and thus should be used with caution when working with multiple datasources.

    A RowId is valid for the lifetime defined by the datasource and as long as the row is not deleted. The DatabaseMetadata.getRowIdLifetime() method is called to determine the RowId's lifetime. The return type is an enumeration type as summarized in the table below.

    RowIdLifetime enum type Definition
    ROWID_UNSUPPORTED Datasource does not support RowId type
    ROWID_VALID_OTHER Implementation-dependent lifetime
    ROWID_VALID_TRANSACTION Lifetime is at least the containing transaction
    ROWID_VALID_SESSION Lifetime is at least the containing session
    ROWID_VALID_FOREVER Unlimited lifetime

    The ROWID_VALID_TRANSACTION, ROWID_VALID_SESSION, and ROWID_VALID_FOREVER definitions are true as long as the row is not deleted. It is important to understand that a new RowId is assigned if a row is deleted and reinserted, which sometimes could happen transparently at the datasource. As an example, in Oracle, if the "enable row movement" clause is set on a partitioned table and an update of the partition key causes the row to move from one partition to another, the RowId will change. Even without the "enable row movement" flag with the "alter table table_name" move, the RowId could change.

    Both the ResultSet and CallableStatement interfaces have been updated to include a method called getRowID(), which returns a javax.sql.RowId type.

    Listing 3 shows how RowId could be retrieved from a ResultSet and from a CallableStatement.

    Listing 3. Get RowId

    //The method signatures to retrieve RowId from a ResultSet is as follows:
    ?? RowId getRowId (int columnIndex)
    ?? RowId getRowId (String columnName)
    ...

    Statement stmt = con.createStatement ();

    ResultSet rs = stmt. ExecuteQuery (…);

    while (rs.next ()) {

    ...

    java.sql.RowId rid = rs.getRowId (1);

    ...

    }

    //The method signatures to retrieve RowId from a CallableStatement is as follows:
    ?? RowId getRowId (int parameterIndex)
    ?? RowId getRowId (String parameterName)

    Connection con;
    ...

    CallableStatement cstmt = con.prepareCall (…);
    ...

    cstmt.registerOutParameter (2, Types.ROWID);

    ...

    cstmt.executeUpdate ();

    ...

    java.sql.RowId rid = cstmt.getRowId (2);

    The RowId can be used to refer uniquely to a row and thus can be used to retrieve the rows or update the row data. When fetching or updating using RowId references, it is important to know the validity of the RowId's lifetime to assure consistent results. It is also advisable to simultaneously use another reference, such as the primary key, to avoid inconsistent results in circumstances where the RowId could change transparently.

    The RowId values can also be set or updated. In the case of an updateable ResultSet, the updateRowId() method could be used to update the RowId for a particular row in a table.

    Both the PreparedStatement and the CallableStatement interfaces support a setRowId() method, with different signatures, to set the RowId as a parameter value. This value could be used to refer to data rows or to update the RowId value for a particular row in a table.

    The facility to set or update the RowId provides the flexibility to control the unique row identifiers and could be used to make such identifiers unique across the tables used. Perhaps, portability of RowId across supporting datasources could also be achieved by explicitly setting consistent values across them. However, because system-generated RowIds are often efficient, and transparent tasks could alter RowIds, they are best used by an application as a read-only attribute.

    Leverage nonstandard vendor implemented resources
    The new JDBC API defines a java.sql.Wrapper interface. This interface provides the ability to access datasource-vendor-specific resources by retrieving the delegate instance using the corresponding wrapped proxy instance.

    This Wrapper interface has 17 sub-interfaces as per the current specification and includes Connection, ResultSet, Statement, CallableStatement, PreparedStatement, DataSource, DatabaseMetaData, and ResultSetMetaData, among others in the list. This is an excellent design as it facilitates datasource-vedor-specific resource implementation at almost all stages of the query-creation and result-set-retrieval lifecycles.

    The unwrap() method returns the object that implements the given interface to allow access to vendor-specific methods. The isWrapperFor() method returns a Boolean value. It returns true if it implements the interface, or if it directly or indirectly is a wrapper for the object.

    As an example, when using Oracle, Oracle JDBC drivers provide update batching extensions that are better performing and more efficient as compared to the standard JDBC batch-updating mechanisms. For earlier JDBC versions, this implies using the Oracle-specific definitions, such as OraclePreparedStatement, in the code. This compromises code portability. With the new API, many such efficient implementations can be wrapped and exposed within the standard JDBC definitions.

    Service provider mechanism for driver loading
    In a nonmanaged or standalone program scenario, prior to JDBC 4.0, you would have to load the JDBC driver class explicitly by invoking the Class.forName method, as shown in Listing 4:

    Listing 4. Class.forName

    Class.forName ("com.driverprovider.jdbc.jdbcDriverImpl");

    With JDBC 4.0, if the JDBC driver vendors package their drivers as services, defined under the server provider mechanism definitions as per the JAR specification, the DriverManager code would implicitly load the driver by searching for it in the classpath. The benefit of this mechanism is that the developer does not need to know about the specific driver class and can write a little less code when using JDBC. Also, since the driver class name is no longer in the code, a name change would not require recompilations. If multiple drivers are specified in the classpath, then DriverManger will try and establish a connection using the first driver it encounters in the classpath and iterate further if required.

    Conclusion
    In this article, I have discussed some of the new and improved features of JDBC 4.0. Many of these new features enhance a developer's productivity and facilitate development. Also, the specification does not eradicate the possible use of extra JDBC frameworks to provide templating facilities and advanced exception-handling capabilities. However, there is some criticism as well. Some believe that annotations effectively lead to hard-coding in code, which causes problems in code maintainability.

    posted @ 2006-05-09 11:17 Leo 閱讀(896) | 評論 (2)編輯 收藏

    ANT安裝、配置

    內容摘要:
    ant是一個基于JAVA的自動化腳本引擎,腳本格式為XML。除了做JAVA編譯相關任務外,ANT還可以通過插件實現很多應用的調用。


    ANT的基本概念:
    ANT的安裝:解包,設置路徑
    ANT的使用:最好的學習只不過是一個簡單實用的例子起步……
    ANT的基本概念:Java的Makefile
    當一個代碼項目大了以后,每次重新編譯,打包,測試等都會變得非常復雜而且重復,因此c語言中有make腳本來幫助這些工作的批量完成。在Java 中應用是平臺無關性的,當然不會用平臺相關的make腳本來完成這些批處理任務了,ANT本身就是這樣一個流程腳本引擎,用于自動化調用程序完成項目的編譯,打包,測試等。除了基于JAVA是平臺無關的外,腳本的格式是基于XML的,比make腳本來說還要好維護一些。


    每個ant腳本(缺省叫build.xml)中設置了一系列任務(target):比如對于一個一般的項目可能需要有以下任務。

    任務1:usage 打印本腳本的幫助信息(缺省)
    任務2:clean <-- init 清空初始化環境
    任務3:javadoc <-- build <-- init 生成JAVADOC
    任務4:jar <-- build <-- init 生成JAR
    任務5:all <-- jar + javadoc <-- build <-- init 完成以上所有任務:jar javadoc
    而多個任務之間往往又包含了一定了依賴關系:比如把整個應用打包任務(jar)的這個依賴于編譯任務(build),而編譯任務又依賴于整個環境初始化任務(init)等。

    注:我看到很多項目的ant腳本中的命名基本上都是一致的,比如:編譯一般叫build或者compile;打包一般叫jar或war;生成文檔一般命名為javadoc或javadocs;執行全部任務all。在每個任務的中,ANT會根據配置調用一些外部應用并配以相應參數執行。雖然ANT可調用的外部應用種類非常豐富,但其實最常用的就2,3個:比如javac javadoc jar等。
    ANT的安裝
    解包后在系統可執行路徑中加入指向ant的bin的路徑就可以了,比如可以在GNU/Linux上把以下配置加入/etc/profile中:
    export ANT_HOME=/home/ant
    export JAVA_HOME=/usr/java/j2sdk1.4.1
    export PATH=$PATH:$JAVA_HOME/bin:$ANT_HOME/bin

    這樣執行ant 后,如果不指定配置文件ant會缺省找build.xml這個配置文件,并根據配置文件執行任務,缺省的任務設置可以指向最常用的任務,比如: build,或指向打印幫助信息:usage,告訴用戶有那些腳本選項可以使用。


    ANT的使用

    最好的學習過程就是看懂那些open source項目中的build.xml腳本,然后根據自己的需要簡化成一個更簡單的,ANT和APACHE上很多非常工程派的項目:簡單易用,而且適應性非常強,因為這些項目的建立往往來源于開發人員日常最直接的需求。
    以下是的一個WebLucene應用的例子:修改自JDOM的build.xml:

    <project default="usage" basedir=".">

    <!-- =================================================================== -->
    <!-- Initialization target -->
    <!-- =================================================================== -->
    <target name="init">
    <tstamp/>
    <property file="${basedir}/build.properties" />
    <property name="Name" value="ProjectFullName"/>
    <property name="name" value="project_name"/>
    <property name="version" value="0.2"/>
    <property name="year" value="2003"/>

    <echo message="----------- ${Name} ${version} [${year}] ------------"/>

    <property name="debug" value="off"/>
    <property name="optimize" value="on"/>
    <property name="deprecation" value="on"/>

    <property name="src.dir" value="./src/WEB-INF/src"/>
    <property name="lib.dir" value="./src/WEB-INF/lib"/>
    <property name="packages" value="com.chedong.*,org.apache.lucene.*"/>

    <property name="build.src" value="./src/WEB-INF/build"/>
    <property name="build.dest" value="./src/WEB-INF/classes"/>
    <property name="build.javadocs" value="./src/doc"/>

    <path id="classpath">
    <pathelement path="${jsdk_jar}"/>
    <fileset dir="${lib.dir}">
    <include name="**/*.jar"/>
    </fileset>
    </path>

    <filter token="year" value="${year}"/>
    <filter token="version" value="${version}"/>
    <filter token="date" value="${TODAY}"/>
    <filter token="log" value="true"/>
    <filter token="verbose" value="true"/>
    </target>

    <!-- =================================================================== -->
    <!-- Help on usage -->
    <!-- =================================================================== -->
    <target name="usage" depends="init">
    <echo message="${Name} Build file"/>
    <echo message="-------------------------------------------------------------"/>
    <echo message=""/>
    <echo message=" available targets are:"/>
    <echo message=""/>
    <echo message=" jar --> generates the ${name}.jar file"/>
    <echo message=" build --> compiles the source code"/>
    <echo message=" javadoc --> generates the API documentation"/>
    <echo message=" clean --> cleans up the directory"/>
    <echo message=""/>
    <echo message=" Please rename build.properties.default to build.properties"/>
    <echo message=" and edit build.properties to specify JSDK 2.3 classpath."/>
    <echo message=""/>
    <echo message=" See the comments inside the build.xml file for more details."/>
    <echo message="-------------------------------------------------------------"/>
    <echo message=""/>
    <echo message=""/>
    </target>

    <!-- =================================================================== -->
    <!-- Prepares the source code -->
    <!-- =================================================================== -->
    <target name="prepare-src" depends="init">
    <!-- create directories -->
    <mkdir dir="${build.src}"/>
    <mkdir dir="${build.dest}"/>

    <!-- copy src files -->
    <copy todir="${build.src}">
    <fileset dir="${src.dir}"/>
    </copy>
    </target>

    <!-- =================================================================== -->
    <!-- Compiles the source directory -->
    <!-- =================================================================== -->
    <target name="build" depends="prepare-src">
    <javac srcdir="${build.src}"
    destdir="${build.dest}"
    debug="${debug}"
    optimize="${optimize}">
    <classpath refid="classpath"/>
    </javac>
    </target>

    <!-- =================================================================== -->
    <!-- Creates the class package -->
    <!-- =================================================================== -->
    <target name="jar" depends="build">
    <jar jarfile="${lib.dir}/${name}.jar"
    basedir="${build.dest}"
    includes="**"/>
    </target>

    <!-- =================================================================== -->
    <!-- Creates the API documentation -->
    <!-- =================================================================== -->
    <target name="javadoc" depends="build">
    <mkdir dir="${build.javadocs}"/>
    <javadoc packagenames="${packages}"
    sourcepath="${build.src}"
    destdir="${build.javadocs}"
    author="true"
    version="true"
    use="true"
    splitindex="true"
    windowtitle="${Name} API"
    doctitle="${Name}">
    <classpath refid="classpath"/>
    </javadoc>
    </target>

    <!-- =================================================================== -->
    <!-- Clean targets -->
    <!-- =================================================================== -->
    <target name="clean" depends="init">
    <delete dir="${build.src}"/>
    <delete dir="${build.dest}/org"/>
    <delete dir="${build.dest}/com"/>
    <delete>
    <fileset dir="${build.dest}" includes="**/*.class"/>
    </delete>
    </target>
    </project>
    <!-- End of file -->

    缺省任務:usage 打印幫助文檔,告訴有那些任務選項:可用的有build, jar, javadoc和clean.

    初始化環境變量:init
    所有任務都基于一些基本環境變量的設置初始化完成,是后續其他任務的基礎,在環境初始化過程中,有2點比較可以方便設置:

    1 除了使用卻缺省的property設置了JAVA源路徑和輸出路徑外,引用了一個外部的build.properties文件中的設置,
    <property file="${basedir}/build.properties" />
    這樣大部分簡單配置用戶只要會看懂build.properties就可以了,畢竟XML比起key value的屬性文件還是要可讀性差一些。用build.properties也可以方便其他用戶從編譯的細節中解放出來。

    2 CLASSPATH設置:使用了其中的:
    <path id="classpath">
    <pathelement path="${jsdk_jar}"/>
    <fileset dir="${lib.dir}">
    <include name="**/*.jar"/>
    </fileset>
    </path>
    則相當于設置了:CLASSPATH=/path/to/resin/lib/jsdk23.jar; /path/to/project/lib/*.jar;

    文件復制:prepare-src
    創建臨時SRC存放目錄和輸出目錄。
    <!-- =================================================================== -->
    <!-- Prepares the source code -->
    <!-- =================================================================== -->
    <target name="prepare-src" depends="init">
    <!-- create directories -->
    <mkdir dir="${build.src}"/>
    <mkdir dir="${build.dest}"/>

    <!-- copy src files -->
    <copy todir="${build.src}">
    <fileset dir="${src.dir}"/>
    </copy>
    </target>

    編譯任務:build
    編譯時的CLASSPATH環境通過一下方式找到引用一個path對象
    <classpath refid="classpath"/>

    打包任務:jar
    對應用打包生成項目所寫名的.jar文件
    <!-- =================================================================== -->
    <!-- Creates the class package -->
    <!-- =================================================================== -->
    <target name="jar" depends="build">
    <jar jarfile="${lib.dir}/${name}.jar"
    basedir="${build.dest}"
    includes="**"/>
    </target>

    生成JAVADOC文檔任務: javadoc
    <!-- =================================================================== -->
    <!-- Creates the API documentation -->
    <!-- =================================================================== -->
    <target name="javadoc" depends="build">
    <mkdir dir="${build.javadocs}"/>
    <javadoc packagenames="${packages}"
    sourcepath="${build.src}"
    destdir="${build.javadocs}"
    author="true"
    version="true"
    use="true"
    splitindex="true"
    windowtitle="${Name} API"
    doctitle="${Name}">
    <classpath refid="classpath"/>
    </javadoc>
    </target>

    清空臨時編譯文件:clean
    <!-- =================================================================== -->
    <!-- Clean targets -->
    <!-- =================================================================== -->
    <target name="clean" depends="init">
    <delete dir="${build.src}"/>
    <delete dir="${build.dest}/org"/>
    <delete dir="${build.dest}/com"/>
    <delete>
    <fileset dir="${build.dest}" includes="**/*.class"/>
    </delete>
    </target>

    TODO:
    更多任務/擴展:(樣例)

    測試任務:JUnit測試
    代碼風格檢查任務:CheckStyle,Jalopy等
    郵件警報任務:可以把以上這些任務的輸出警告發送到制定的用戶列表中,這個任務可以設置每天自動運行。

    參考資料:

    Jakarta ANT:
    http://ant.apache.org



    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=707995

    posted @ 2006-05-08 10:54 Leo 閱讀(660) | 評論 (3)編輯 收藏

    最近寫程序已經很少直接用JDBC了,一直都是用ibaits, Hibernate等來招呼,因為現在的集成框架已經很穩定了。不過對JDBC的直接使用還是不可以忽略的,JDBC3.0提供的n多的新特征還是要熟悉了解的,以前學jdbc的時候就是上網找些demo和介紹來學,使用很單一,對JDBC3.0的好多新的特征都忽略了,比如下面一個例子:

    Statement stmt = con.createStatement();
    ResultSet rs = stmt.executeQuery("SELECT * FROM user WHERE username='aa'");
    stmt.executeUpdate("UPDATE user SET lastdatetime=now() where username='aa'");

    這是一個用戶登錄時,經常用到的代碼,先是根據用戶名aa查找該用戶的詳細信息,然后再更新該用戶的最后登錄時間(lastdatetime)。這這個里面,我們用了兩個sql語句,這個是我一直用的方法,但是如果用JDBC2.0給我們提供的便利,我們只要寫一條sql就夠了,其他的都交給jdbc,看下面的代碼:

    Statement stmt2 = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
    ResultSet rs2 = stmt.executeQuery("SELECT * FROM user WHERE username='aa'");
    rs2.next();
    rs2.updateDate("lastdatetime", new Date(Calendar.getInstance().getTimeInMillis()));
    rs2.updateRow();

    這里面最主要的特征就是ResultSet.TYPE_FORWARD_ONLY和ResultSet.CONCUR_UPDATABLE,通過初始化Statement時傳不同的參數,可以對ResultSet進行不用的錯作限制。con.createStatement的時候,有三種可以掉用的函數:

    1、createStatement();
    2、createStatement(int resultSetType, int resultSetConcurrency)
    3、createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)

    其中resultSetType可選值是:
    ?? 1、ResultSet.TYPE_FORWARD_ONLY? 在ResultSet中只能先前移動游標,
    ?? 2、ResultSet.TYPE_SCROLL_INSENSITIVE 在ResultSet中可以隨心所欲的先前向后移動游標,
    ?? 3、ResultSet.TYPE_SCROLL_SENSITIVE 在ResultSet中可以隨心所欲的先前向后移動游標,同時ResultSet的值有所改變的時候,他可以得到改變后的最新的值
    其中resultSetConcurrency可選值是:
    ?? 1、ResultSet.CONCUR_READ_ONLY? 在ResultSet中的數據記錄是只讀的,可以修改
    ?? 2、ResultSet.CONCUR_UPDATABLE? 在ResultSet中的數據記錄可以任意修改,然后更新會數據庫
    其中resultSetHoldability可選值是:
    ?? 1、ResultSet.HOLD_CURSORS_OVER_COMMIT 表示修改提交時,不關閉ResultSet的游標
    ?? 2、ResultSet.CLOSE_CURSORS_AT_COMMIT? 表示修改提交時,關閉ResultSet的游標

    對于查詢操作第一種初始化方法createStatement(),相當于第二種方法的createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY),第三種方法的createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT)

    下面寫一段demo的代碼,我把一些特征函數都用出來,但是只是用來查考和說明名靈活性的。

    ?Statement stmt2 = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
    ?ResultSet rs2 = stmt.executeQuery("SELECT * FROM user");
    ?rs2.next();
    ?rs2.updateDate("lastdatetime", new Date(Calendar.getInstance().getTimeInMillis()));
    ?rs2.updateRow();
    ?rs2.afterLast();
    ?while(rs2.previous()){ /**....*/ }
    ?rs.beforeFirst();
    ?while(rs2.next()){? /**....*/ }
    ?rs.last();
    ?rs.first();
    ?rs.absolute(5);?//游標移動到第5條
    ?rs.absolute(-1);? //游標移動到最后一條
    ?rs.relative(-5);? //游標向上移動5條
    ?rs.relative(2);?? //游標向下移動2條
    ?rs.deleteRow();?//刪除當前行
    ?rs.last();? //游標移動到最后
    ?rs.updateString("summary", "This is ..."); //設置更新的字段值
    ?rs.cancelRowUpdates();? //取消剛才輸入的更新
    ?rs.getRow(); //得到當前行號
    ?rs.moveToInsertRow();? //游標移動到要新增的那條記錄上
    ?rs.updateInt("id", 1);
    ?rs.updateString(2, "my name");
    ?rs.insertRow(); //插入新記錄


    JDBC2.0提供的還有一個功能就是數據庫的批量操作

    ??con.setAutoCommit(false);
    ??Statement stmt3 = con.createStatement();
    ??stmt3.addBatch("insert .....");
    ??stmt3.addBatch("insert .....");
    ??int[] rows = stmt3.executeBatch();
    ??con.commit();

    但是有一點要注意,stmt3.executeBatch()他不會自動給你回滾數據操作,當你有5條update語句的時候,如果第三條發生錯誤,那么將無法自動回滾前兩條update語句的影響,所以一定要自己手工進行事務管理。

    在您的事務中使用 Savepoint
    JDBC3.0中最令人興奮的附加特點就是 Savepoint 了。有時候需要的是對事務多一點的控制,而不是在當前的事務中簡單地對每一個改變進行回滾。在JDBC3.0下,您就可以通過 Savepoint 獲得這種控制。Savepoint 接口允許您將事務分割為各個邏輯斷點,以控制有多少事務需要回滾。看下面的代碼:

    conn.setAutoCommit(false);
    conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
    Statement stmt = conn.createStatement();
    int rows = stmt.executeUpdate( "INSERT INTO authors (first_name, last_name) valueS(′Lewis′, ′Carroll′)");
    Savepoint svpt = conn.setSavepoint("NewAuthor");
    try{
    ?rows = stmt.executeUpdate( "UPDATE authors set type = ′fiction′ WHERE last_name = ′Carroll′");
    }catch(Exception e){
    ?conn.rollback(svpt);
    ?rows = stmt.executeUpdate( " update .......... other sql ");
    }
    conn.commit();

    上面代碼顯示,當UPDATE authors失敗的時候,系統事務回滾UPDATE authors的sql的影響,而INSERT INTO authors的sql仍然有效


    檢索自動產生的關鍵字
    為了解決對獲取自動產生的或自動增加的關鍵字的值的需求,JDBC 3.0現在將獲取這種值變得很輕松。要確定任何所產生的關鍵字的值,只要簡單地在語句的 execute() 方法中指定一個可選的標記,Statement.RETURN_GENERATED_KEYS和Statement.NO_GENERATED_KEYS。在執行這條語句后,所產生的關鍵字的值就會通過從 Statement 的實例方法 getGeneratedKeys() 來檢索 ResultSet 而獲得。ResultSet 包含了每個所產生的關鍵字的列。看下面代碼:

    Statement stmt = conn.createStatement();
    stmt.executeUpdate("INSERT INTO authors (first_name, last_name) valueS (′George′, ′Orwell′)", Statement.RETURN_GENERATED_KEYS);
    ResultSet rs = stmt.getGeneratedKeys();
    if ( rs.next() ) {
    ?int key = rs.getInt();
    }

    ?參考資料: http://java.sun.com/j2se/1.5.0/docs/api/java/sql/package-summary.html

    posted @ 2006-05-08 10:49 Leo 閱讀(1539) | 評論 (2)編輯 收藏

    主站蜘蛛池模板: 白白国产永久免费视频| a级毛片免费完整视频| 亚洲videos| 亚洲午夜电影一区二区三区| 亚洲精品国产精品| 免费看美女午夜大片| 中文字幕视频免费在线观看| 4444www免费看| 最近2019中文字幕mv免费看| 免费在线观看黄网站| 91亚洲国产成人久久精品网站| 一本色道久久88—综合亚洲精品| 国产va免费精品| 国产精品久久免费| 亚洲熟妇丰满多毛XXXX| 亚洲日韩乱码久久久久久| 四虎国产精品成人免费久久 | 久久亚洲国产成人影院| 亚洲毛片基地4455ww| 老司机福利在线免费观看| 久久国产精品成人免费| 免费下载成人电影| 91免费国产在线观看| 亚洲最大免费视频网| 114一级毛片免费| 亚洲色欲色欲www| 最近免费中文字幕大全视频 | 久久亚洲AV成人无码国产最大| 33333在线亚洲| 黄色成人网站免费无码av| 国产人成免费视频网站| 亚洲免费观看网站| 四虎影院免费在线播放| mm1313亚洲精品无码又大又粗| 亚洲AV无码乱码在线观看| 九九免费久久这里有精品23| 91福利免费网站在线观看| 亚洲av永久无码精品表情包 | 精品国产污污免费网站aⅴ| 免费播放特黄特色毛片| 国产性生大片免费观看性|