用Java編程語言和JDBC開發的程序是可以跨平臺運行的,并且是不受供應商限制的.
4.1 JDBC的設計
JDBC由兩層組成,上面一層是JDBC API,負責與JDBC管理器驅動程序API進行通信,將各個不同的SQL語句發送給它;該管理器(對程序員是透明的)再與實際連接到數據庫的各個第三方驅動程序進行通信,并且返回查詢的信息,或者執行由查詢規定的操作.
JDBC驅動程序分為以下幾種類型:
類型1驅動程序
負責將JDBC轉換為ODBC,并且使用一個ODBC驅動程序與數據庫進行通信
類型2驅動程序
部分使用Java編程語言編寫的和部分使用本機代碼編寫的驅動程序,用于與數據庫的客戶機API進行通信
類型3驅動程序
純粹的Java客戶程序庫,它使用跨數據庫協議,將數據庫訪問請求傳輸給服務器組件,然后該服務器組件將訪問請求轉換成特定的數據庫協議
類型4驅動程序
純粹的Java庫,用于JDBC訪問請求直接轉換成特定數據庫協議
4.2 結構化查詢語言
JDBC是個到SQL(結構化查詢語言)的接口,而SQL實際上是與所有最新型的關系數據庫之間的接口.
4.3 安裝JDBC
建議最好不要使用Java2 SDK配備的JDBC/ODBC橋接器驅動程序,更加反對將該驅動程序用于Access這樣的桌面數據庫.
4.4 JDBC編程的基本概念
1. 數據庫URL
語法: jdbc:subprotocol name:other stuff
其中subprotocol特定驅動程序, other stuff參數的格式要根據它使用的子協議而定.
2. 建立連接
Class.forName(驅動程序類); 注冊驅動程序
String url = …;
String username = …;
String password = …;
Connetion conn = DriverManager.getConnection(url, username, password);
讀取屬性文件建立連接
Properties props = new Properties();
FileInputStream in = new FileInputStream(“database.properties”);
props.load(in);
in.close();
String drivers = props.getProperty(“jdbc.drivers”);
String url = props.getProperty(“jdbc.drivers”);
String username = props.getProperty(“jdbc.username”);
String password = props.getProperty(“jdbc.password”);
Connetion conn = DriverManager.getConnection(url, username, password);
3. 執行SQL命令
Statement stat = conn.createStatement();
String sql = …;
ResultSet rs = stat.executeQuery(sql);/stat.executeUpdate(sql);
while(rs.next()){
…
}
4. 高級SQL類型
Blob b=resultSet.getBlob(1);
InputStream bin=b.getBinaryStryeam();
Clob c=resultSet.getClob(2);
Reader cReader=c.getCharacterStream();
寫入:
FileInputStream fis=new
FileInputStream(f,Connection conn);
byte[] buffer=new byte[1024];
data=null;
int sept=0;int len=0;
while((sept=fis.read(buffer))!=-1){
if(data==null){
len=sept;
data=buffer;
}else{
byte[] temp;
int tempLength;
tempLength=len+sept;
temp=new byte[tempLength];
data=temp;
len=tempLength;
}
if(len!=data.length()){
byte temp=new byte[len];
data=temp;
}
}
String sql="insert into fileData (filename,blobData) value(?,?)";
PreparedStatement ps=conn.prepareStatement(sql);
ps.setString(1,f.getName());
ps.setObject(2,data);
ps.executeUpdate();
讀出:
try {
Clob c=resultSet.getClob(2);
Reader reader=c.getCharacterStream():
if (reader == null) {
return null;
}
StringBuffer sb = new StringBuffer();
char[] charbuf = new char[4096];
for (int i = reader.read(charbuf); i >
0; i = reader.read(charbuf)) {
sb.append(charbuf, 0, i);
}
return sb.toString();
} catch (Exception e) {
return "";
}
4.5 執行查詢操作
采用宿主變量方式:
String userId = 1;
String sql = “select * form user where user_id=?”;
PreparedStatement pStat = conn.prepareStatement(sql);
pStat.setString(1,userId);
ResultSet rs = pStat.executeQuery();
4.6 可滾動的和可更新的結果集
1. 可滾動的結果集
Statement stat = conn.createStatement(type,concurrency);
或
PreparedStatement stat = conn.prepareStatement(command,type, concurrency);
其中
Type包括:
ResultSet.TYPE_FORWARD_ONLY 不能滾動
ResultSet.TYPE_SCROLL_INSENSITIVE 可以滾動,但變化不敏感
ResultSet.TYPE_SCROLL_SENSITIVE 可以滾動,但變化敏感
Concurrency包括:
ResultSet.CONCUR_READ_ONLY 不能更新
ResultSet.CONCUR_UPDATABLE 可以更新
常用方法:
rs.previous() 滾動結果集
rs.relative(n) 將光標向后或向前移動n行
rs.absolute(n) 將光標設置到某個特定的行號上
rs.getRow() 獲得當前的行號
2. 可更新的結果集
常用方法:
rs.getConcurrency() 查看結果集是否可更新
rs.updateXxx() 只能用于修改行的值,不能修改數據庫
rs.updateRow() 將當前行中所有信息更新發送給數據庫
rs.cancelRowUpdates() 撤銷對當前行的更新
rs.moveToInsertRow() 將光標移到一個特定的位置
rs.insertRow() 將該新行傳遞給數據庫
rs.moveToCurrentRow() 將光標移回之前位置
rs.deleteRow() 刪除光標下的行
例子:
rs. moveToInsertRow();
rs.updateString(“Title”,title);
rs.updateString(“Isbn”,isbn);
rs.insertRow();
rs.moveToCurrentRow();
4.7 元數據
元數據是在SQL中用于描述數據庫或者它的各個部分之一的數據;分為關于數據庫的元數據和關于結構集合的元數據.
DatabaseMetaData conn.getMetaData() 用于提供關于數據庫的元數據
ResultSetMetaData rs.getMetaData() 用于提供關于結構集合的元數據
4.8 事務
如果將各個更新命令組合成一個事務,可以實現數據庫數據的完整性;在提交事務時,如果在它中間某個位置上運行失敗,它可以執行回退操作,并且該數據庫將自動撤銷提交事務以來進行的所有更新及所產生的影響.
在默認情況下,數據庫連接處于自動提交方式,并且每個SQL命令一旦被執行,便被提交給該數據庫.一旦命令被提交,就無法進行回退操作.
批量更新: 一序列命令將作為一個批量來集中和提交,命令不包括Select查詢.
String sql = …;
stat.addBatch(sql);
while(…){
sql = …
stat.addBatch(sql);
}
stat.executeBatch();
4.9 高級連接管理
在企業級環境中部署JDBC應用程序時,數據庫連接的管理納入了JNDI(Java命令與目錄接口)之中.一個目錄負責管理整個企業中的數據源的位置.使用目錄后,就可以對用戶名、口令、數據庫名字和JDBC URL實施集中管理.
Context jndi = …;
DataSource source = (DataSource)jndi.lookup(“jdbc/corejava”);
Connection conn = source.getConnection(username,password);
log4j是一個很好的開源的日志項目,下面就我在實際中使用的一些情況作一個小結(我所寫的是以spring為框架的運用,之所以要提到這點,是因為在spring中專門有處理log4j的地方,而我也用到了這些地方)。
在使用的第一步你要明白你所發布的web項目所使用的服務器,因為不同的服務器對于使用log4j是有些不同的,我在實際使用中主要是用tomcat和 jboss兩類,對于tomcat,它本身是沒有配置log4j的,所以使用起來和常規的一樣;而在jboss中它是本身配置了log4j的,所以有時候 我們在看項目代碼時,其整個項目并沒有log4j的配置文件,而在一些類中仍然定義了Logger,例如static Logger log = org.apache.log4j.Logger.getLogger(UserDaoImple.class);,這就表明開發者打算使用jboss默 認的log4j的配置,我們可以在jboss下的對應的log目錄下的server.log中看到日志,jboss本身的log4j的配置是將 debug,info級的日志寫在server.log中,而像error等級別比較高的日志打印到控制臺上,而寫到server.log中的日志比較多,并不方便查看。于是我們想到使用自己的log4j配置寫到某個具體的文件中(注意文件要先建立,才能往里面寫東西,log4j自己不能建立文件),但 這里因為jboss有它自己的log4j配置,所以如果我們配置的log4j包含Console的Appender時,就會出錯,錯誤類似于
ERROR: invalid console appender config detected, console stream is looping.
解決方法一是不用Console的Appender,或者改jboss的配置文件,在jboss-service.xml文件里,把
<mbean code="org.jboss.logging.Log4jService" name="jboss.system:type=Log4jService,service=Logging">
<attribute name="ConfigurationURL">resource:log4j.xml</attribute>
<attribute name="CatchSystemOut">false</attribute>
<attribute name="Log4jQuietMode">true</attribute>
</mbean>。
我建議不用Console的Appender,當然這是對jboss3.2.x是這樣,對于jboss4.0.x如果我們要用自己的log4j配置照上述改還是會有問題,會有類似于log4j:ERROR A "org.jboss.logging.util.OnlyOnceErrorHandler" object is not assignable to a "org.apache.log4j.spi.ErrorHandler" variable的異常,解決方法是把/server/default/jbossweb-tomcat55.sar/META-INF/jboss-service.xml 中的以下兩個熟悉改成true
<attribute name="Java2ClassLoadingCompliance">true</attribute>
<attribute name="UseJBossWebLoader">true</attribute>
以上就是使用jboss服務器可能出現的問題,解決了這些再來使用log4j就比較簡單了。
下面說說對于采用了spring框架的項目如何使用log4j,在spring中使用log4j,有些方便的地方,
1. 動態的改變記錄級別和策略,即修改log4j.properties,不需要重啟Web應用,這需要在web.xml中設置一下。
2. 把log文件定在 /WEB-INF/logs/ 而不需要寫絕對路徑。
3. 可以把log4j.properties和其他properties一起放在/WEB-INF/ ,而不是Class-Path。
首先我們在web.xml中需要設定一下
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>WEB-INF/log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>60000</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
其中第二部分就是能夠動態修改log4j.properties的關鍵,容器會每60秒掃描log4j的配置文件 。對 于log4j的配置文件如何寫,這就不多說了,大家可以去google,有一點就是我們如果用RollingFileAppender或者 FileAppender時,可以通過${webapp.root}來定位到服務器的發布的該項目下,這是spring把web目錄的路徑壓入到了 webapp.root的系統變量。然后,在log4j.properties 里就可以這樣定義logfile位置
log4j.appender.logfile.File=${webapp.root}/WEB-INF/logs/myfuse.log
如果有多個web應用,怕webapp.root變量重復,可以在context-param里定義webAppRootKey。
常用log4j配置,一般可以采用兩種方式,.properties和.xml,下面舉兩個簡單的例子:
一、log4j.properties
### 設置org.zblog域對應的級別INFO,DEBUG,WARN,ERROR和輸出地A1,A2 ##
log4j.category.org.zblog=ERROR,A1
log4j.category.org.zblog=INFO,A2
log4j.appender.A1=org.apache.log4j.ConsoleAppender
### 設置輸出地A1,為ConsoleAppender(控制臺) ##
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
### 設置A1的輸出布局格式PatterLayout,(可以靈活地指定布局模式)##
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n
### 配置日志輸出的格式##
log4j.appender.A2=org.apache.log4j.RollingFileAppender
### 設置輸出地A2到文件(文件大小到達指定尺寸的時候產生一個新的文件)##
log4j.appender.A2.File=E:/study/log4j/zhuwei.html
### 文件位置##
log4j.appender.A2.MaxFileSize=500KB
### 文件大小##
log4j.appender.A2.MaxBackupIndex=1
log4j.appender.A2.layout=org.apache.log4j.HTMLLayout
##指定采用html方式輸出
二、log4j.xml
<?xml version="1.0" encoding="GB2312" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="org.zblog.all" class="org.apache.log4j.RollingFileAppender">
<!-- 設置通道ID:org.zblog.all和輸出方式:org.apache.log4j.RollingFileAppender -->
<param name="File" value="E:/study/log4j/all.output.log" /><!-- 設置File參數:日志輸出文件名 -->
<param name="Append" value="false" /><!-- 設置是否在重新啟動服務時,在原有日志的基礎添加新日志 -->
<param name="MaxBackupIndex" value="10" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%p (%c:%L)- %m%n" /><!-- 設置輸出文件項目和格式 -->
</layout>
</appender>
<appender name="org.zblog.zcw" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="E:/study/log4j/zhuwei.output.log" />
<param name="Append" value="true" />
<param name="MaxFileSize" value="10240" /> <!-- 設置文件大小 -->
<param name="MaxBackupIndex" value="10" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%p (%c:%L)- %m%n" />
</layout>
</appender>
<logger name="zcw.log"> <!-- 設置域名限制,即zcw.log域及以下的日志均輸出到下面對應的通道中 -->
<level value="debug" /><!-- 設置級別 -->
<appender-ref ref="org.zblog.zcw" /><!-- 與前面的通道id相對應 -->
</logger>
<root> <!-- 設置接收所有輸出的通道 -->
<appender-ref ref="org.zblog.all" /><!-- 與前面的通道id相對應 -->
</root>
</log4j:configuration>
三、配置文件加載方法:
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
public class Log4jApp {
public static void main(String[] args) {
DOMConfigurator.configure("E:/study/log4j/log4j.xml");//加載.xml文件
//PropertyConfigurator.configure("E:/study/log4j/log4j.properties");//加載.properties文件
Logger log=Logger.getLogger("org.zblog.test");
log.info("測試");
}
}
四、項目使用log4j
在web 應用中,可以將配置文件的加載放在一個單獨的servlet中,并在web.xml中配置該servlet在應用啟動時候加載。對于在多人項目中,可以給每一個人設置一個輸出通道,這樣在每個人在構建Logger時,用自己的域名稱,讓調試信息輸出到自己的log文件中。
五、常用輸出格式
# -X號:X信息輸出時左對齊;
# %p:日志信息級別
# %d{}:日志信息產生時間
# %c:日志信息所在地(類名)
# %m:產生的日志具體信息
# %n:輸出日志信息換行
給出得Log4J配置文件實現了輸出到控制臺,文件,回滾文件,發送日志郵件,輸出到數據庫日志表,自定義標簽等全套功能。
log4j.rootLogger=DEBUG,CONSOLE,A1,im
#DEBUG,CONSOLE,FILE,ROLLING_FILE,MAIL,DATABASE
log4j.addivity.org.apache=true
###################
# Console Appender
###################
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=DEBUG
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
#log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n
#####################
# File Appender
#####################
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=file.log
log4j.appender.FILE.Append=false
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
# Use this layout for LogFactor 5 analysis
########################
# Rolling File
########################
log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLING_FILE.Threshold=ERROR
log4j.appender.ROLLING_FILE.File=rolling.log
log4j.appender.ROLLING_FILE.Append=true
log4j.appender.ROLLING_FILE.MaxFileSize=10KB
log4j.appender.ROLLING_FILE.MaxBackupIndex=1
log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
####################
# Socket Appender
####################
log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender
log4j.appender.SOCKET.RemoteHost=localhost
log4j.appender.SOCKET.Port=5001
log4j.appender.SOCKET.LocationInfo=true
# Set up for Log Facter 5
log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout
log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n
########################
# Log Factor 5 Appender
########################
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000
########################
# SMTP Appender
#######################
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold=FATAL
log4j.appender.MAIL.BufferSize=10
log4j.appender.MAIL.From=chenyl@hollycrm.com
log4j.appender.MAIL.SMTPHost=mail.hollycrm.com
log4j.appender.MAIL.Subject=Log4J Message
log4j.appender.MAIL.To=chenyl@hollycrm.com
log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
########################
# JDBC Appender
#######################
log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test
log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver
log4j.appender.DATABASE.user=root
log4j.appender.DATABASE.password=
log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')
log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.File=SampleMessages.log4j
log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j'
log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout
###################
#自定義Appender
###################
log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender
log4j.appender.im.host = mail.cybercorlin.net
log4j.appender.im.username = username
log4j.appender.im.password = password
log4j.appender.im.recipient = corlin@cybercorlin.net
log4j.appender.im.layout=org.apache.log4j.PatternLayout
log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n