Servlet Java Web开发(5)数据库的使用

1经典使用

核心API及其使用,maven:mysql-connector-java

连接数据库

String db_url="jdbc:mysql://localhost:3306/djangoserverTimezone=GMT%2B8";

Connection con=DriverManager.getConnection(db_url,user,pwd);

操作

Statement stmt=con.createStatement();

对于增加,修改,删除使用stmt.executeUpdate,返回作用的行数

对于查询使用stmt.executeQuery,返回ResultSet对象,比如叫rs。获取数据方式如下

while(rs.next()){

 

...String id=rs.getInt("id");..}

例子

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;

public class MainFIle {

    /**
     * @param args
     * @throws ClassNotFoundException 
     */
    public static void main(String[] args) throws ClassNotFoundException {
        // TODO Auto-generated method stub
        String jdbc_driver="com.mysql.cj.jdbc.Driver";
        String db_url="jdbc:mysql://localhost:3306/django?serverTimezone=GMT%2B8";
        String user="root";
        String pwd="123456";
        Connection con=null;
        java.sql.Statement stmt=null;
        try {
            con=DriverManager.getConnection(db_url,user,pwd);
            stmt=con.createStatement();
            String sql="select * from personinfo";
            ResultSet rs=stmt.executeQuery(sql);
            while(rs.next()) {
                int id=rs.getInt("id");
                String name=rs.getString("name");
                String job=rs.getString("job");
                System.out.println("well,here is your data: id is "+id+"with name: "+name+" and job:"+job);
            }
            rs.close();
            stmt.close();
            con.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
            try {
                if(stmt!=null)
                    stmt.close();
            }catch(Exception ex) {
                ex.printStackTrace();
            }
            
            try {
                if(con!=null)
                    con.close();}
                catch(Exception ex) {
                    ex.printStackTrace();
                }
            }
    }
}
View Code

PreparedStatement

是Statement的子接口,可以提高效率和防止SQL攻击。

使用:使用sql语句模板,用户数据字符串用?代替

String sql="insert into user value(?,?,?)";

String update="update user set username=?,password=? where id=?";

声明变量,和设置数据,序号从1开始

PreparedStatement ps=con.prepareStatement(update);

ps.setString(1,"haha");ps.setString(2,"234");

ps.executeUpdate()或者其他

需要执行其他数据,先清理,ps.clearParameters();

批处理:

在一次设置好所有数据之后,可以暂不执行,调用ps.addBatch(),再继续设置数据

最后一次性ps.executeBatch()

存取二进制数据

二进制在表中的数据类型为BLOB,在代码中操作的数据类型为InputStream

建表时,该列字段为MDDIUMBLOB (16MB)或者LONGBLOB(4GB),字段名为mydata

将数据读入一个InputStream in中,使用PreparedStatement构建sql模板比如

String sql="insert into yourtable (filename,mydata) values(?,?)";

使用ps .setBinaryStream(2,in);

 读取时,使用ResultSet的getBinaryStream("mydata")方法获取InputStream对象

 

方法2:存取的时候使用PreparedStatement的setBlob和

ResultSet的getBlob方法。

Blob 对象和字节数组可以相互转换。Blob b=new SerialBlob(..)参数是byte[]

getBlob返回一个Blob对象b后,使用getBytes返回byte array

DAO模式

就是写一个类,封装访问数据的代码,在数据库和业务逻辑之间。

1.实体域,比如我们操作的是User表,先写一个User类

public class User{

private String id;

private String userName;...}

2.DAO模式需要一个DAO接口

public interface UserDao{

public void add(User user);

public void mod(User user);

public void del(String id);....}

3该接口的一个实现,实现具体访问数据库的细节。

JdbcUtils辅助类

目的:将mysql路径,用户名密码放到配置文件中。

 2.事务和连接池

事务开始,

执行多条sql语句

要么提交要么回滚

1开启事务

setAutoCommit(false),默认为true,也就是每一条sql语句都是一个单独的事务

2commit  or rollback

try {

  con.setAutoCommit(false);//开启事务…

  ….

  …

  con.commit();//try的最后提交事务

} catch() {

  con.rollback();//回滚事务

}

 连接池库C3P0

在src文件夹建立c3p0-config.xml文件,内容

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!-- 这是默认配置信息 -->
    <default-config> 
        <!-- 连接四大参数配置 -->
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/customers</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="user">root</property>
        <property name="password">123</property>
        <!-- 池参数配置 -->
        <property name="acquireIncrement">3</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">2</property>
        <property name="maxPoolSize">10</property>
    </default-config>
    
    <!-- 专门为oracle提供的配置信息 -->
    <named-config name="oracle-config"> 
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb1</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="user">root</property>
        <property name="password">123</property>
        <property name="acquireIncrement">3</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">2</property>
        <property name="maxPoolSize">10</property>
    </named-config>

</c3p0-config>

使用,需要的时候直接从池中getConnection,用完关闭。

ComboPooledDataSource ds = new ComboPooledDataSource();
Connection con = ds.getConnection();
...........
con.close();

基于ThreadLocal的Jdbc实用类

该类保证了一个变量,在不同的线程有一个唯一对象

ThreadLocal<T>简介,内部是个map,使用当前线程作为键。

ThreadLocal<Connection> con=new ThreadLocal<Connection>();

con保证了每一个线程con都有一个Connection对象。主要三个方法

void set(T value);  

T get();

void remove();

该实用类的全部代码

package cn.itcast.jdbc;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

/**
 * 使用本类的方法,必须提供c3p0-copnfig.xml文件
 * @author qdmmy6
 */
public class JdbcUtils {
    // 饿汉式
    private static DataSource ds = new ComboPooledDataSource();
    
    /**
     * 它为null表示没有事务
     * 它不为null表示有事务
     * 当开启事务时,需要给它赋值
     * 当结束事务时,需要给它赋值为null
     * 并且在开启事务时,让dao的多个方法共享这个Connection
     */
    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
    
    public static DataSource getDataSource() {
        return ds;
    }
    
    /**
     * dao使用本方法来获取连接
     * @return
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException {
        /*
         * 如果有事务,返回当前事务的con
         * 如果没有事务,通过连接池返回新的con
         */
        Connection con = tl.get();//获取当前线程的事务连接
        if(con != null) return con;
        return ds.getConnection();
    }
    
    /**
     * 开启事务
     * @throws SQLException 
     */
    public static void beginTransaction() throws SQLException {
        Connection con = tl.get();//获取当前线程的事务连接
        if(con != null) throw new SQLException("已经开启了事务,不能重复开启!");
        con = ds.getConnection();//给con赋值,表示开启了事务
        con.setAutoCommit(false);//设置为手动提交
        tl.set(con);//把当前事务连接放到tl中
    }
    
    /**
     * 提交事务
     * @throws SQLException 
     */
    public static void commitTransaction() throws SQLException {
        Connection con = tl.get();//获取当前线程的事务连接
        if(con == null) throw new SQLException("没有事务不能提交!");
        con.commit();//提交事务
        con.close();//关闭连接
        con = null;//表示事务结束!
        tl.remove();
    }
    
    /**
     * 回滚事务
     * @throws SQLException 
     */
    public static void rollbackTransaction() throws SQLException {
        Connection con = tl.get();//获取当前线程的事务连接
        if(con == null) throw new SQLException("没有事务不能回滚!");
        con.rollback();
        con.close();
        con = null;
        tl.remove();
    }
    
    /**
     * 释放Connection
     * @param con
     * @throws SQLException 
     */
    public static void releaseConnection(Connection connection) throws SQLException {
        Connection con = tl.get();//获取当前线程的事务连接
        if(connection != con) {//如果参数连接,与当前事务连接不同,说明这个连接不是当前事务,可以关闭!
            if(connection != null &&!connection.isClosed()) {//如果参数连接没有关闭,关闭之!
                connection.close();
            }
        }
    }
}
JdbcUtils

DBUtils类

C3P0是连接池类,主要目的是获得Connection对象,

而DButils类需要一个Connection对象,对ResultSet中的数据操作进行了转换和简化。

你现在可以把ResultSet中数据放到一个List中,或者Map中,或者一个bean中

DBUtils主要是QueryRunner类

update为例子

update函数原型

public int update(Connection con ,String sql);

public int update(Connection con,String sql,Object...params);//为了传入PreparedStatement 数量不一的?形式的参数

String sql="insert into user values(?,?,?)";

QueryRunner qr=new QueryRunner(con);

qr.update(sql,"23","sam","123");

con.close();

query为例子

在DAO模式下,有类Customer属性分别是String id,String name,String date

数据库表t_customer分别对应。

public <T> T query(Connection,String sql,ResultSetHandler<T> rsh)或者

public <T> T query(Connection,String sql,ResultSetHandler<T> rsh,Object...params)

接口ResultSetHandler有很多不同形式的实现,方便 返回不同的数据类型。

例1.返回所有

String sql="select * from t_customer";

返回Customer对象的列表。BeanListHandler<T>实现的是ResultSetHandler<List<T>>

构造函数为public BeanListHandler(Class<T> type),参数为bean的Class类型,这里传入Customer.class

public List<Customer> findAll(){

  QueryRunner qr=new QueryRunner(con);

  String sql="select * from t_customer";

  return qr.query(sql,newBeanListHandler<Customer>(Customer,class));

}

 

例2,返回id为XX的一个对象

public Customer load(String cid){

  QueryRunner qr=new QueryRunner(con);

  String sql="select * from t_customer where cid=?";

  return qr.query(sql,new BeanHandler<Customer>(Customer.class));

}

其他实现举例
MapHandler 将结果转成Map<String,Object>其中键就是数据表的列

MapListHandler结果转成List<Map<String,Object>,

ColumnListHandler转成List<Object>,需要指定列的名字,new ColumnListHandler("name");

ScalarHandler用于集聚查询,select count(*) from tableXXX;

在代码中的使用:除了第三个,直接传入一个new的对象。

 

posted on 2018-07-27 11:32  legion  阅读(227)  评论(0编辑  收藏  举报

导航