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

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

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

    Leo's Blog

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      13 隨筆 :: 3 文章 :: 18 評(píng)論 :: 0 Trackbacks

    2006年4月3日 #

    ??? 昨天讀了一篇關(guān)于JDBC4.0設(shè)計(jì)與性能提高的文章,由于小弟英語翻譯水準(zhǔn)實(shí)在有限,就不在這里獻(xiàn)丑了,就把原文給大家轉(zhuǎn)載出來供大家閱讀:

    轉(zhuǎn)載自: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 閱讀(895) | 評(píng)論 (2)編輯 收藏

    ANT安裝、配置

    內(nèi)容摘要:
    ant是一個(gè)基于JAVA的自動(dòng)化腳本引擎,腳本格式為XML。除了做JAVA編譯相關(guān)任務(wù)外,ANT還可以通過插件實(shí)現(xiàn)很多應(yīng)用的調(diào)用。


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


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

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

    注:我看到很多項(xiàng)目的ant腳本中的命名基本上都是一致的,比如:編譯一般叫build或者compile;打包一般叫jar或war;生成文檔一般命名為javadoc或javadocs;執(zhí)行全部任務(wù)all。在每個(gè)任務(wù)的中,ANT會(huì)根據(jù)配置調(diào)用一些外部應(yīng)用并配以相應(yīng)參數(shù)執(zhí)行。雖然ANT可調(diào)用的外部應(yīng)用種類非常豐富,但其實(shí)最常用的就2,3個(gè):比如javac javadoc jar等。
    ANT的安裝
    解包后在系統(tǒng)可執(zhí)行路徑中加入指向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

    這樣執(zhí)行ant 后,如果不指定配置文件ant會(huì)缺省找build.xml這個(gè)配置文件,并根據(jù)配置文件執(zhí)行任務(wù),缺省的任務(wù)設(shè)置可以指向最常用的任務(wù),比如: build,或指向打印幫助信息:usage,告訴用戶有那些腳本選項(xiàng)可以使用。


    ANT的使用

    最好的學(xué)習(xí)過程就是看懂那些open source項(xiàng)目中的build.xml腳本,然后根據(jù)自己的需要簡化成一個(gè)更簡單的,ANT和APACHE上很多非常工程派的項(xiàng)目:簡單易用,而且適應(yīng)性非常強(qiáng),因?yàn)檫@些項(xiàng)目的建立往往來源于開發(fā)人員日常最直接的需求。
    以下是的一個(gè)WebLucene應(yīng)用的例子:修改自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 -->

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

    初始化環(huán)境變量:init
    所有任務(wù)都基于一些基本環(huán)境變量的設(shè)置初始化完成,是后續(xù)其他任務(wù)的基礎(chǔ),在環(huán)境初始化過程中,有2點(diǎn)比較可以方便設(shè)置:

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

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

    文件復(fù)制:prepare-src
    創(chuàng)建臨時(shí)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>

    編譯任務(wù):build
    編譯時(shí)的CLASSPATH環(huán)境通過一下方式找到引用一個(gè)path對(duì)象
    <classpath refid="classpath"/>

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

    生成JAVADOC文檔任務(wù): 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>

    清空臨時(shí)編譯文件: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:
    更多任務(wù)/擴(kuò)展:(樣例)

    測試任務(wù):JUnit測試
    代碼風(fēng)格檢查任務(wù):CheckStyle,Jalopy等
    郵件警報(bào)任務(wù):可以把以上這些任務(wù)的輸出警告發(fā)送到制定的用戶列表中,這個(gè)任務(wù)可以設(shè)置每天自動(dòng)運(yùn)行。

    參考資料:

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



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

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

    最近寫程序已經(jīng)很少直接用JDBC了,一直都是用ibaits, Hibernate等來招呼,因?yàn)楝F(xiàn)在的集成框架已經(jīng)很穩(wěn)定了。不過對(duì)JDBC的直接使用還是不可以忽略的,JDBC3.0提供的n多的新特征還是要熟悉了解的,以前學(xué)jdbc的時(shí)候就是上網(wǎng)找些demo和介紹來學(xué),使用很單一,對(duì)JDBC3.0的好多新的特征都忽略了,比如下面一個(gè)例子:

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

    這是一個(gè)用戶登錄時(shí),經(jīng)常用到的代碼,先是根據(jù)用戶名aa查找該用戶的詳細(xì)信息,然后再更新該用戶的最后登錄時(shí)間(lastdatetime)。這這個(gè)里面,我們用了兩個(gè)sql語句,這個(gè)是我一直用的方法,但是如果用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時(shí)傳不同的參數(shù),可以對(duì)ResultSet進(jìn)行不用的錯(cuò)作限制。con.createStatement的時(shí)候,有三種可以掉用的函數(shù):

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

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

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

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

    ?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);?//游標(biāo)移動(dòng)到第5條
    ?rs.absolute(-1);? //游標(biāo)移動(dòng)到最后一條
    ?rs.relative(-5);? //游標(biāo)向上移動(dòng)5條
    ?rs.relative(2);?? //游標(biāo)向下移動(dòng)2條
    ?rs.deleteRow();?//刪除當(dāng)前行
    ?rs.last();? //游標(biāo)移動(dòng)到最后
    ?rs.updateString("summary", "This is ..."); //設(shè)置更新的字段值
    ?rs.cancelRowUpdates();? //取消剛才輸入的更新
    ?rs.getRow(); //得到當(dāng)前行號(hào)
    ?rs.moveToInsertRow();? //游標(biāo)移動(dòng)到要新增的那條記錄上
    ?rs.updateInt("id", 1);
    ?rs.updateString(2, "my name");
    ?rs.insertRow(); //插入新記錄


    JDBC2.0提供的還有一個(gè)功能就是數(shù)據(jù)庫的批量操作

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

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

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

    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();

    上面代碼顯示,當(dāng)UPDATE authors失敗的時(shí)候,系統(tǒng)事務(wù)回滾UPDATE authors的sql的影響,而INSERT INTO authors的sql仍然有效


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

    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 閱讀(1538) | 評(píng)論 (2)編輯 收藏

    < script?language = " javascript " ?type = " text/javascript " >

    function?Hashtable()
    {
    ????
    this ._hash???????? = ? new ?Object();
    ????
    this .add???????? = ?function(key,value){
    ????????????????????????
    if (typeof(key) != " undefined " ){
    ????????????????????????????
    if ( this .contains(key) == false ){
    ????????????????????????????????
    this ._hash[key] = typeof(value) == " undefined " ? null :value;
    ????????????????????????????????
    return ? true ;
    ????????????????????????????}?
    else ?{
    ????????????????????????????????
    return ? false ;
    ????????????????????????????}
    ????????????????????????}?
    else ?{
    ????????????????????????????
    return ? false ;
    ????????????????????????}
    ????????????????????}
    ????
    this .remove???????? = ?function(key){delete? this ._hash[key];}
    ????
    this .count???????? = ?function(){var?i = 0 ; for (var?k?in? this ._hash){i ++ ;}? return ?i;}
    ????
    this .items???????? = ?function(key){ return ? this ._hash[key];}
    ????
    this .contains???? = ?function(key){? return ?typeof( this ._hash[key]) != " undefined " ;}
    ????
    this .clear???????? = ?function(){ for (var?k?in? this ._hash){delete? this ._hash[k];}}

    }

    var?a?
    = ? new ?Hashtable();

    a.add(
    " aa " );
    a.add(
    " bb " , 2342 );
    a.add(
    " bb " , 2342 );

    a.remove(
    " aa " );

    alert(a.count());

    alert(a.contains(
    " bb " ));

    alert(a.contains(
    " aa " ));

    alert(a.items(
    " bb " ));


    </ script >
    posted @ 2006-04-29 20:59 Leo 閱讀(467) | 評(píng)論 (2)編輯 收藏

         摘要: < HTML > < HEAD > < TITLE > print </ TITLE > < meta? http-equiv =...  閱讀全文
    posted @ 2006-04-29 20:57 Leo 閱讀(1332) | 評(píng)論 (1)編輯 收藏

         摘要: 事件源對(duì)象 event.srcElement.tagName event.srcElement.type 捕獲釋放 event.srcElement.setCapture();? event.srcElement.releaseCapture();? 事件按鍵 ...  閱讀全文
    posted @ 2006-04-29 20:50 Leo 閱讀(526) | 評(píng)論 (2)編輯 收藏

         摘要: 為 我們的項(xiàng)目寫的一個(gè)輕量的分頁API。目的在于將分頁與數(shù)據(jù)查詢的邏輯完全剝離。我以前看過robbin發(fā)的通過detachedCriteria實(shí)現(xiàn)的 分頁那片貼子,里面把分頁和數(shù)據(jù)查詢結(jié)合在一起了。而我覺得分開更輕量,而且替換也比較容易。但是這個(gè)實(shí)現(xiàn)中有一個(gè)反模式,在邏輯中生成了代碼,無奈之 選,為了簡便。其中字符生成可以自己擴(kuò)展i18n實(shí)現(xiàn),應(yīng)該非常容易。分頁實(shí)現(xiàn)的接口:package?c...  閱讀全文
    posted @ 2006-04-03 02:22 Leo 閱讀(505) | 評(píng)論 (2)編輯 收藏

    主站蜘蛛池模板: 国产无遮挡裸体免费视频| 亚洲性色AV日韩在线观看| 永久免费看bbb| 久久免费国产视频| 又粗又长又爽又长黄免费视频 | 亚洲日日做天天做日日谢| 色噜噜AV亚洲色一区二区| 成年女人永久免费观看片| 男女超爽刺激视频免费播放| 精品免费视在线观看| 精品一区二区三区高清免费观看| 亚洲AV噜噜一区二区三区 | 女人18毛片水真多免费播放| 日韩免费无码一区二区三区| 国产日韩一区二区三免费高清| 一级视频在线免费观看| 美女免费视频一区二区| 亚洲AV无码AV男人的天堂不卡| 亚洲中文字幕在线无码一区二区| 亚洲天堂一区二区| 日韩精品一区二区亚洲AV观看| 亚洲精品国偷自产在线| 激情综合色五月丁香六月亚洲| 中文字幕亚洲专区| 亚洲国产成人乱码精品女人久久久不卡| 天天摸天天操免费播放小视频| 日韩一区二区a片免费观看 | 亚洲成人午夜电影| 亚洲天堂福利视频| 亚洲欧洲日韩国产一区二区三区| 亚洲a级成人片在线观看| 亚洲国产亚洲片在线观看播放| 亚洲国产精品成人久久久| 亚洲天堂电影在线观看| 亚洲综合伊人制服丝袜美腿| 亚洲天堂2016| 亚洲av成人中文无码专区| 亚洲aⅴ无码专区在线观看| 国产亚洲精品欧洲在线观看| 男人j进女人p免费视频| 一级有奶水毛片免费看|