jdbc主要与两个库有关java.sql.* 和 javax.sql.*有关,java.sql定义了数据库连接接口和类,一些接口由数据库厂商来实现。
使用jdbc访问数据库时候主要用到下面几个代码。
//加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//获得到数据库的连接
Connection conn = DriverManager.getConnection(url,user,password);
//执行sql语句
Statement stmt = conn.createStatement();
ResultSet ret = stmt.execute("select* from bookstore");
这个接口是所有数据库厂商都必须实现的接口,
com.mysql.jdbc.Driver 是mysql的驱动类
oracle.jdbc.driver.OracleDriver是oracle的驱动类
使用Class.forName("com.mysql.jdbc.Driver");可以加载该驱动。
驱动是DriverManager来管理的,它的所以方法都是静态的,在加载驱动的时候,DriverManager调用静态registerDriver方法会自动注册一个Driver实例。
连接也是由DriverManager来管理的,传入url,用户名,密码就可以建立到数据库服务器
Connection conn = DriverManager.getConnection(url,user,password);
sql语句是由Statement来执行的,有三种:Statement,PreparedStatement,CallableStatement
Statement stmt = conn.createStatement();
ResultSet ret = stmt.execute("select *from bookstore");
sql语句必须经过语法分析,编译,优化等步骤才能执行,如果只有参数不同其的sql语句,使用Statement是比较低效的。可以使用PreparedStatement,PreparedStatement中的?代表参数,可以使用SetXXX来设置。
在数据库中,描述数据库和表的数据叫做元数据,使用
DatabaseMetaData dbmeta = conn.getMetaData();来获取数据库信息,使用
ResultSetMetaData resMeta = res.getMetaData();来获取一个数据表的信息。
事务是一组数据库操作的单元,它可以保证事务中的所有操作都生效或者都不生效。当事务中有异常发生的时候,可以回滚rollback,如果没有的话commit。
jdbc中时自动提交的,我们可以通过
// 不自动提交
conn.setAutoCommit(false);
让jdbc 不自动提交。
可以在result中更新,删除,插入数据,并保存到数据库中。这样可以使得工作更为方便。
获取一个可以更新数据库的statement,必须提供一些参数
Statement stmt =conn.createStatement (ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
第一个参数:
ResultSet.TYPE_FORWARD_ONLY:只能调用resultSet的next方法,来移动结果集
ResultSet.TYPE_SCROLL_INSENSITIVE,能调用resultSet的next,previous等方法,来移动结果集。但是对数据库变化不敏感。
ResultSet.TYPE_SCROLL_SENSITIVE:能调用resultSet的next,previous等方法,来移动结果集。但是对数据库变化敏感。例如如果结果集合中返回了10条数据,另一个线程删掉了2条数据,那么这个结果集合就只有8个了。
其中第二个参数
ResultSet.CONCUR_UPDATABLE,表示又这个stmt执行的结果ResultSet是可以更新数据库的。
ResultSet.CONCUR_READ_ONLY
,表示
ResultSet不可以更新数据库。
//update 结果集
res.first();
//将结果集中第一行行的title修改为1.11,调用updateRow才会生效
res.updateFloat("price", (float) 1.11);
res.updateString("title","updated row");
res.updateRow();
只有执行了 updateRow才会执行update操作。
//删除最后一个结果集
res.last();
res.deleteRow();
只有执行了 deleteRow才会执行删除操作。
//插入一行
//将游标移动到可以插入的缓存行
res.moveToInsertRow();
res.updateString("author","daniangdaye");
res.updateString("title","inserted row");
res.updateDate("publis_date",new java.sql.Date(new Date().getTime()));
res.updateFloat("price", (float) 1.11);
res.insertRow();
只有执行了 insertRow才会执行插入操作。
使用DirverManager,可以连接数据库,但是每一次close一个连接connection,都会真正的关闭一个与数据库的连接,而建立连接是非常消耗资源的。DataSource使用连接池管理连接可以更有效的利用资源。当调用close的时候并不是关闭连接而是把连接归还连接池。
/**
* 使用 DriverManager 来管理mysql的连接
* @throws ServletException
*/
privatevoid initUsingDriverManager()throws ServletException
{
//从web.xml中顶一顶servlet中去取得初始化参数
String driverClass=this.getInitParameter("driverClass");
url =this.getInitParameter("url");
user =this.getInitParameter("user");
password =this.getInitParameter("password");
//加载数据库驱动
try
{
Class.forName(driverClass);
}
catch(Exception e)
{
e.printStackTrace();
//加载失败抛出UnavailableException后这个servlet将永久不可用。以后如果有请求访问服务器会返回404。
thrownew UnavailableException("加载数据库驱动失败");
}
}
需要在context中配置数据源Source的信息:
<ContextdocBase="servletJspLearn"path="/servletJspLearn"reloadable="true"source="org.eclipse.jst.jee.server:servletJspLearn">
<Resource
name="jdbc/bookstore"
type="javax.sql.DataSource"
password=""
driverClassName="com.mysql.jdbc.Driver"
maxIdle="2"
maxWait="5000"
username="root"
url="jdbc:mysql://localhost:3306/bookstore"
maxActive="4"/>
Context>
在WEB-INFO中的web.xml中也需要加入对这个数据源的引用:
<web-appxmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xmlns=http://java.sun.com/xml/ns/javaee
xmlns:web=http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"version="3.0">
<resource-ref>
<res-ref-name>jdbc/bookstoreres-ref-name>
<res-type>javax.sql.DataSourceres-type>
<res-auth>Containerres-auth>
resource-ref>
注意在eclipse中配置数据源是在server中:的server.xml中进行配置。
例如:对于servletJspLearn, 在server.xml中找到
然后加入resource的配置
在代码中如下面方式得到连接。
/**
* 使用数据源来取得数据库的连接
*/
Context initialContext = new javax.naming.InitialContext();
Context envContext = (Context)initialContext.lookup("java:comp/env");
DataSource ds = (DataSource) envContext.lookup("jdbc/bookstore");
conn = ds.getConnection();
下面是一个使用jdbc创建数据库建立表,插入数据的servlet,手动提交,回滚等操作的实例:
package junjun.chapter8;
import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.Statement; import java.util.Date; import java.sql.Timestamp;
import javax.servlet.ServletException; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 创建数据库 * 创建表 * 插入数据 * @author andyWebsense * */ public class CreateDBServlet extends HttpServlet { private String url ; //到数据库的连接 private String user; // 用户名 private String password;//密码 @Override public void init() throws ServletException { super.init(); // 从web.xml中顶一顶servlet中去取得初始化参数 String driverClass=this.getInitParameter("driverClass"); url = this.getInitParameter("url"); user = this.getInitParameter("user"); password = this.getInitParameter("password"); //加载数据库驱动 try { Class.forName(driverClass); } catch(Exception e) { e.printStackTrace(); // 加载失败抛出UnavailableException后这个 servlet将永久不可用。以后如果有请求访问服务器会返回404。 throw new UnavailableException("加载数据库驱动失败"); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Connection conn = null; Statement stmt = null; try { conn = DriverManager.getConnection(url,user,password); // 不自动提交 conn.setAutoCommit(false); stmt = conn.createStatement(); // 如果已经存在该数据库 删掉 stmt.execute("drop database if exists bookstore"); //创建数据库 stmt.execute("create database bookstore"); stmt.execute("use bookstore");
//创建数据表 stmt.executeUpdate( " create table bookinfo(" + "id INT not null primary key auto_increment , " + "author varchar(50)," + "title varchar(50) not null," + " publis_date Date not null, " + "price float(4,2) not null ," + "amount smallint," + "remark varchar(200) )" + " AUTO_INCREMENT = 0 engine=InnoDB"); //批量插入一批数据 stmt.addBatch("insert into bookinfo values(1,'junjun','java','2012-1-1',12.11,10,null)"); stmt.addBatch("insert into bookinfo values(2,'xiaolan','python','2012-11-1',2.11,10,null)"); stmt.addBatch("insert into bookinfo values(3,'junjun','ruby','2012-12-1',1.11,10,null)"); stmt.executeBatch(); /* *使用prepareStatment 优化 */ PreparedStatement pstmt = conn.prepareStatement("insert into bookinfo values(? , ? , ? ,?,12.11,10,null)"); pstmt.setInt(1, 4); pstmt.setString(2, "xiaohai"); pstmt.setString(3,"google"); pstmt.setDate(4, new java.sql.Date(new Date().getTime())); pstmt.execute(); pstmt.setInt(1, 5); pstmt.setString(2, "haihai"); pstmt.setString(3,"ws"); pstmt.setDate(4, new java.sql.Date(new Date().getTime())); pstmt.execute(); //提交给数据库 conn.commit(); PrintWriter p = resp.getWriter(); p.println("success!"); } catch(Exception e) { e.printStackTrace(); if(conn!=null) { try { // 如果出现错误回滚 conn.rollback(); } catch(Exception e1) { e1.printStackTrace(); } stmt = null; } } finally {
if(stmt!=null) { try { stmt.close(); } catch(Exception e1) { e1.printStackTrace(); } stmt = null; } if(conn!=null) { try { conn.close(); } catch(Exception e1) { e1.printStackTrace(); } conn = null; } } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub this.doPost(req, resp); } }
package junjun.chapter8;
import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.Date;
import javax.naming.Context; 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;
import com.mysql.jdbc.Driver; /** * 列出数据库的内容 * @author andyWebsense * */ public class ListServlet extends HttpServlet { private String url ; //到数据库的连接 private String user; // 用户名 private String password;//密码 @Override public void init() throws ServletException { super.init(); initUsingDriverManager(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Connection conn = null; Statement stmt = null; try { //conn = DriverManager.getConnection(url,user,password); /** * 使用 数据源来取得数据库的连接 */ Context initialContext = new javax.naming.InitialContext(); Context envContext = (Context)initialContext.lookup("java:comp/env"); DataSource ds = (DataSource) envContext.lookup("jdbc/bookstore"); conn = ds.getConnection(); //获取一个可以更新数据库的statement stmt = conn.createStatement (ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); //打印所有书籍的信息 PrintWriter p = resp.getWriter(); printBook(stmt,p); //打印数据库的元数据 p.println("
all the meta Data of database bookstore
"); //返回数据库的所有信息 DatabaseMetaData dbmeta = conn.getMetaData(); //获取这个数据库中所有的table的信息 ResultSet resTable = dbmeta.getTables(null, null, null, new String[] {"TABLE"}); while(resTable.next()) { p.println(resTable.getString("TABLE_NAME")); p.println("
"); } // 打印bookinfo的信息:名字,类型,长度 p.println("
all the meta info of table bookinfo
"); ResultSet res = stmt.executeQuery("select * from bookinfo"); ResultSetMetaData resMeta = res.getMetaData(); int columntCount = resMeta.getColumnCount(); for(int i = 1;i < columntCount; i++) { p.println(resMeta.getColumnName(i)+" "+resMeta.getColumnTypeName(i)+" "+resMeta.getColumnDisplaySize(i)); p.println("
"); } /* * 在结果集中操作 */ //update 结果集 res.first(); //将结果集中第一行行的title修改为1.11,调用updateRow才会生效 res.updateFloat("price", (float) 1.11); res.updateString("title","updated row"); res.updateRow(); //删除最后一个结果集 res.last(); res.deleteRow(); //插入一行 //将游标移动到可以插入的缓存行 res.moveToInsertRow(); res.updateString("author", "daniangdaye"); res.updateString("title","inserted row"); res.updateDate("publis_date", new java.sql.Date(new Date().getTime())); res.updateFloat("price", (float) 1.11); res.insertRow(); //打印所有书籍的信息 printBook(stmt,p); } catch(Exception e) { e.printStackTrace(); } finally {
if(stmt!=null) { try { stmt.close(); } catch(Exception e1) { e1.printStackTrace(); } stmt = null; } if(conn!=null) { try { conn.close(); } catch(Exception e1) { e1.printStackTrace(); } conn = null; } } } /**打印所有的书 * @param stmt * @param p * @throws SQLException */ private void printBook(Statement stmt,PrintWriter p) throws SQLException { ResultSet res = stmt.executeQuery("select * from bookinfo"); p.println("
all the information of books
"); while(res.next()) { String title = res.getString("title"); String author = res.getString("author"); Float price = res.getFloat("price"); Date publishDate = res.getDate("publis_date"); p.println(title+" " +author+ " "+price+" "+publishDate); p.println("
"); } } /** * 使用 DriverManager 来管理mysql的连接 * @throws ServletException */ private void initUsingDriverManager() throws ServletException { // 从web.xml中顶一顶servlet中去取得初始化参数 String driverClass=this.getInitParameter("driverClass"); url = this.getInitParameter("url"); user = this.getInitParameter("user"); password = this.getInitParameter("password"); //加载数据库驱动 try { Class.forName(driverClass); } catch(Exception e) { e.printStackTrace(); // 加载失败抛出UnavailableException后这个 servlet将永久不可用。以后如果有请求访问服务器会返回404。 throw new UnavailableException("加载数据库驱动失败"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub this.doPost(req, resp); } }
这个servlet的配置信息: