JDBC数据库
jdbc相关的组件
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");
java.sql.Driver接口
这个接口是所有数据库厂商都必须实现的接口,
com.mysql.jdbc.Driver 是mysql的驱动类
oracle.jdbc.driver.OracleDriver是oracle的驱动类
使用Class.forName("com.mysql.jdbc.Driver");可以加载该驱动。
DriverManager 管理驱动
驱动是DriverManager来管理的,它的所以方法都是静态的,在加载驱动的时候,DriverManager调用静态registerDriver方法会自动注册一个Driver实例。
连接也是由DriverManager来管理的,传入url,用户名,密码就可以建立到数据库服务器
Connection conn = DriverManager.getConnection(url,user,password);
Statement 执行sql语句
sql语句是由Statement来执行的,有三种:Statement,PreparedStatement,CallableStatement
Statement stmt = conn.createStatement();
ResultSet ret = stmt.execute("select *from bookstore");
PreparedStatement 执行sql语句
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的连接
/**
* 使用 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("加载数据库驱动失败");
}
}
使用DataSource来管理连接:
需要在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/bookstore</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
注意在eclipse中配置数据源是在server中:的server.xml中进行配置。
例如:对于servletJspLearn, 在server.xml中找到
<Context docBase="servletJspLearn" path="/servletJspLearn" reloadable="true">
然后加入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);
}
}
使用DataSource管理连接、获取数据库元数据,打印表信息,在结果集合中执行修改,删除,插入操作,
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("<br/>all the meta Data of database bookstore<br/>");
//返回数据库的所有信息
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("<br>");
}
// 打印bookinfo的信息:名字,类型,长度
p.println("<br/>all the meta info of table bookinfo<br/>");
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("<br>");
}
/*
* 在结果集中操作
*/
//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("<br/>all the information of books<br/>");
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("<br>");
}
}
/**
* 使用 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的配置信息:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns: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/bookstore</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<!-- chapter 8 -->
<servlet>
<servlet-name>CreateDBServlet</servlet-name>
<servlet-class>junjun.chapter8.CreateDBServlet</servlet-class>
<init-param>
<description>数据库的驱动</description>
<param-name>driverClass</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</init-param>
<init-param>
<description>数据库的连接</description>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mysql</param-value>
</init-param>
<init-param>
<description>数据库用户名</description>
<param-name>user</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<description>数据库密码</description>
<param-name>password</param-name>
<param-value></param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>CreateDBServlet</servlet-name>
<url-pattern>/createdb</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ListServlet</servlet-name>
<servlet-class>junjun.chapter8.ListServlet</servlet-class>
<init-param>
<description>数据库的驱动</description>
<param-name>driverClass</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</init-param>
<init-param>
<description>数据库的连接</description>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/bookstore</param-value>
</init-param>
<init-param>
<description>数据库用户名</description>
<param-name>user</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<description>数据库密码</description>
<param-name>password</param-name>
<param-value></param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ListServlet</servlet-name>
<url-pattern>/listServlet</url-pattern>
</servlet-mapping>
</web-app>