本文章过于混乱,请移步到另一篇博客 Java JDBC编程
1.mysql 数据库的 jdbc url 形式
"jdbc:mysql://localhost:3036/databasename"包含三个部分: 协议:子协议://子名称
2.使用jdbc操作数据库的一般方法
第一步:加载驱动程序
driverClass=com.mysql.jdbc.Driver
Class.forName(driverClass);
第二步:连接数据库
DriverManager 类:
数据库连接方法
public static Connection getConnection(String url ,Properties info) throws SQLException;
public static Connection getConnection(String url ,String user ,String password) throws SQLException
public static Connection getConnection(String url ) throws SQLException
如果用第二种方法,可以这样写
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bookstore","user","password");
表示连接mysql数据库系统 ,user用户下的bookstore数据库
通常,我们会将用到的驱动类名称,数据库连接url ,user password ,定义在web.xml文件中作为全局参数,供这个web应用的所有servlet调用.
第三步: 获取操作执行sql语句的类
第一个类: Statement = connection.createStatement()
1.可以通过方法executeQuery() ,一次执行一个SQL语句
2.Statement 对象的 addBatch() 方法将插入数据的SQL 语句组成一个命令列表,然后调用executeBatch()方法批量执行这些SQL语句.大批量执行可以
显著提高心里能,减少服务器负载
3.executeUpdate() ,可执行指定的insert,update 或者delete语句,而且可以自行sql ddl 语句,如:create table ;
注:
执行语句方法会返回一个结果,也就是ResultSet 对象 ;
ResultSet对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet有数据库厂商实现.它维护了一个指向当前数据行的游标,初始指在第一行,
通过方法boolea next() 移动游标到下一行(返回下一行是否有效的布尔值),然后循环获取结果集中的数据行.它有多种方法操作游标来获取数据(具体参考api文档)
ResultSet提供了多种方法获取当前行中的数据,可以根据字段类型的不同,用不同的方法获取数据
例如: getArray() getString() getFloat() getDouble() getObject() 等等;
还能以列的索引为参数获取数据
String getString(int columnIndex)throws SQLException
String getString(String columnName)throws SQLException
第二个类: PreparedStatement extends Statement = connection.prepareStatement(SQL)
该类可以获取一条预编译的带参数的sql语句,然后调研方法修改参数.这个方法对于执行只有参数不同的多条sql语句非常快捷.其中参数 用 ? 表示
通过调用setXXX(index , value )方法设置对应索引值(>=1)的参数值.
示例:
PreparedStatement pstmt = connection.prepareStatement("insert bookinfo values(?,?,?)");
pstmt.setInt(1,1);
pstmt.setString(2,"bookname");
pstmt.setDate(3,java.sql.Date("2014-10-19"));
pstmt.executeUpdate();//无返回内容的执行语句
第三个类:
public interface CallableStatementextends PreparedStatement用于执行 SQL 存储过程的接口。JDBC API 提供了一个存储过程 SQL 转义语法,
该语法允许对所有 RDBMS 使用标准方式调用存储过程。此转义语法有一个包含结果参数的形式和一个不包含结果参数的形式。
如果使用结果参数,则必须将其注册为 OUT 参数。其他参数可用于输入、输出或同时用于二者。参数是根据编号按顺序引用的,第一个参数的编号是 1。
{?= call <procedure-name>[(<arg1>,<arg2>, ...)]}
{call <procedure-name>[(<arg1>,<arg2>, ...)]}
IN 参数值是使用继承自 PreparedStatement 的 set 方法设置的。在执行存储过程之前,必须注册所有 OUT 参数的类型;它们的值是在执行后通过此类提供的 get 方法获取的。
CallableStatement 可以返回一个 ResultSet 对象或多个 ResultSet 对象。多个 ResultSet 对象是使用继承自 Statement 的操作处理的。
为了获得最大的可移植性,某一调用的 ResultSet 对象和更新计数应该在获得输出参数的值之前处理。
使用示例:
CallableStatement cstmt = connection.prepareCall("call p_changesal(?,?)");
cstmt.registerOutParmter(2,java.sql.Types.INTERGER);
cstmt.setInt(1,8899);
cstmt.execute();
int sal = cstmt.getInt(2);
第四个类:获取元数据 在sql 中,用于描述数据库或者它的各个组成部分之一的数据称为元数据
public interface ResultSetMetaDataextends Wrapper可用于获取关于 ResultSet 对象中列的类型和属性信息的对象。
以下代码片段创建 ResultSet 对象 rs,创建 ResultSetMetaData 对象 rsmd,并使用 rsmd 查找 rs 有多少列,以及 rs 中的第一列是否可以在 WHERE 子句中使用。
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");
ResultSetMetaData rsmd = rs.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
boolean b = rsmd.isSearchable(1);
3.事务处理
事务处理保证所有的食物都在一个工作单元来执行,即使出现了硬件故障或者系统失灵,都不会改变这种执行方式.当在一个事务中执行多个操作时,
要么所有的操作都被提交,要么整事务回滚到最初的状态.
默认情况下,Connection 对象处于自动提交模式下,这意味着它在执行每个语句后都会自动提交更改。
如何运用事务处理:
首先禁用自动提交模式(setAutoCommit(boolean autoCommit=false) ),显式调用 commit() 方法提交更改,保存数据库更改。
发生错误后调用rollback()执行回滚操作.
4.可滚动,可更新的结果集
如果要获得可滚动的结果集,需要在创建Statement对象时,调用Connection对象的另一个重载的createStatement()方法
Statement createStatement(int resultSetType,int resultSetConcurrency)throws SQLException
通过设置resultSetType的值实现结果集的滚动
-经验证:MySQL Connector/J 5.1.x 不支持可更新的结果集操作
5.JDBC 数据源和连接池
建立数据库连接是相当耗费资源的,而且一个数据库服务器能够同时建立的连接数是有限的,在大兴的Web应用中,可能同时会有成百上千个访问数据库的请求,如果web应用程序
为每一个客户请求分配一个数据库连接,将导致性能的急剧下降.为了能够重复利用数据库连接,提高对请求的响应时间和服务器性能,可以采用连接池技术.连接池技术预先建立多个数据库连接对象
,然后将连接对象保存到连接池中,当客户请求到来时,从池中选择一个连接对象为客户服务,当请求完成后,客户程序调用close()方法,将连接对象放回池中.
在普通连接中,客户程序得到的是物理连接,调用连接对象的close() 方法将关闭连接,而采用连接池技术,客户程序得到的是连接池中物理连接的一个句柄,调用连接对象的close()
的方法,物理连接并未关闭,数据源的实现只是删除了客户程序中的连接对象和池中的连接对象之间的联系.
<Resource>元素的属性
name 指定资源相对于java:comp/env 上下文的JNDI 名
auth 指定资源的管理者,它有两个可选的值: Application 和Container
type 指定资源所属的java类的完整限定名
maxActive 指定在连接池中数据库连接的最大数目,指定这个值需要参照使用的数据库所配置的最大谅解书.取值为0,表示没有限制
maxIdle 指定在连接池中保留的空闲的数据库连接的最大数目.取值为-1,表示永久等待
username 指定连接数据库的用户名
password 指定连接数据库的密码
driverClassName 指定jdbc驱动程序类名
url 指定连接数据库的URL
配置方式:
1.在%CATALIAN_HOME%\conf\context.xml中添加下列内容
<Resource name="jdbc/bookstore" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="root" password="1234567890"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/bookstore?autoReconnect=true"
/>
name属性可以任意,不允许有中文
2.在web程序工程下添加:
<resource-ref>
<res-ref-name>jdbc/bookstore</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
3.调用下列语句获得连接
Context ctx = new InitialContext();
DataSource ds = (DataSource )ctx.lookup("java:comp/env/jdbc/bookstore");
conn = ds.getConnection();
注意:lookup 中的 "java:comp/env/"是固定写法,在后面加上资源名称"jdbc/bookstore"
-------------------------------------------------------------------------这是分割线,下面为代码-------------------------------------------------
1.在conf/context.xml中添加资源信息
<Resource name="jdbc/bookstore" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="zhang" password="1234567890"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/bookstore?autoReconnect=true"
/>
2.在web应用下的web.xml文件中添加资源引用
<resource-ref>
<res-ref-name>jdbc/bookstore</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
3.编写servlet程序
package zhangweicong.web;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
public class GetDBInfoServlet extends HttpServlet {
private String url;
private String user;
private String password;
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Connection conn= null;
Statement stmt = null;
ResultSet rs=null;
try{
//连接池方式
Context ctx = new InitialContext();
DataSource ds = (DataSource )ctx.lookup("java:comp/env/jdbc/bookstore");
conn = ds.getConnection();
/*
* 建立独立物理连接
conn = DriverManager.getConnection(url,user,password);
*/
response.setContentType("text/html;charset=gb2312");
PrintWriter out = response.getWriter();
out.println("<html><head>");
out.println("<title>数据库表信息</title>");
out.println("</head><body>");
String tableName=request.getParameter("tableName");
if( tableName==null||tableName.equals("")){
out.println("<a href='http://localhost:8080/SystemDemo/servlet/GetDBInfoServlet?tableName=bookinfo'>点这里</a></body></html>");
return;
}else{
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from "+tableName);
ResultSetMetaData rsMeta = rs.getMetaData();
int columnCount = rsMeta.getColumnCount();
out.println("<table border=1><caption>表的结构</caption>");
out.println("<tr><th>字段名</th><th>字段类型</th><th>最大字符宽度</th></tr>");
ArrayList<String > al =new ArrayList<String>();
for(int i=1;i<columnCount;i++){
out.println("<tr>");
String columnName = rsMeta.getColumnName(i);
out.println("<td>"+columnName+"</td>");
al.add(columnName);
out.println("<td>"+rsMeta.getColumnTypeName(i)+"</td>");
out.println("<td>"+rsMeta.getColumnDisplaySize(i)+"</td>");
}
out.println("</table>");
}
}catch(SQLException se){
se.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
}finally{
if(rs != null){
try{
rs.close();
}catch(SQLException se){
se.printStackTrace();
}
rs=null;
}
if(stmt != null){
try{
stmt.close();
}catch(SQLException se){
se.printStackTrace();
}
stmt=null;
}
if(conn != null){
try{
conn.close();
}catch(SQLException se){
se.printStackTrace();
}
conn=null;
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
public void init() throws ServletException {
//以直接连接数据库方式时,去掉这里的注释
/*ServletContext servletContext = this.getServletContext();
String driverClass = servletContext.getInitParameter("driverClass");
url = servletContext.getInitParameter("url");
user = servletContext.getInitParameter("user");
password = servletContext.getInitParameter("password");
try{
Class.forName(driverClass);
}catch(ClassNotFoundException ce){
throw new UnavailableException("加载数据库驱动失败");
}*/
}
}
4.配置访问路径在web.xml中
<servlet>
<servlet-name>GetDBInfoServlet</servlet-name>
<servlet-class>zhangweicong.web.GetDBInfoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GetDBInfoServlet</servlet-name>
<url-pattern>/servlet/GetDBInfoServlet</url-pattern>
</servlet-mapping>
5.大功告成.在我的机器环境中访问地址为: http://localhost:8080/SystemDemo/servlet/GetDBInfoServlet?tableName=bookinfo
注意:请开启你的服务器和数据库服务器(数据库bookstore要存在bookinfo表,这是对我而言,你的自己看着办吧);