jdbc(增删改查,批处理,javabean,连接池,事务)


JDBC 常见知识点(一)

JDBC基本知识点(二)

JDBC常见知识点(三)

1,JDBC (JAVA DataBase Connectivity :   java 数据库连接)

2,如何连接数据库?

需要有一个 对应数据库的驱动jar 文件,实现Driver 接口注册,再通过DiverManger 类来获取数据库的连接。

比如:

数据库的驱动jar 包 (Mysql 对应: Mysql-connector-java-5.17.jar,不同的数据库对应不用的jar 包)放入到 web root/WEB-INF/lib/ 目录下面

3,DOS开启数据库服务的方法:

1,点击windos 键,在弹出的搜索框中,输入cmd,右键 “管理员身份运行” 打开
2,输入 net start mysql ,这样就能开启mysql 服务了。

4,注册加载数据库驱动有下面三种方式

显示注册:
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
还可以使用这两种方式:
Class.forName("com.mysql.jdbc.Driver").newInstance();
Class.forName("com.mysql.jdbc.Driver");  // 我们查看源码会发现,执行forName 会调用newInstance() ,所以跟上面的方法一样。

5,对数据库的 增 删 改 查

当我们使用Statement (或者 PreparedStatement)对数据库的增删改查 ,
其中 增加,删除,修改 都是执行executeUpdate()方法 操作,
查询是 executeQuary() 方法的操作,
并且查询操作会返回一个结果集(ResultSet)。

6,Statement  和 PreparedStatement 的区别:

我们可以利用 Statement 来实现对数据库的增删改查,我们只需要组织出正确的sql 语句,就可以实现。
但是我们所写的sql 语句不可以使用参数代替。也就是(?)代替。 PreparedStatement 继承于 Statement 重写了Statement 的所有方法。 PreparedStatement 允许使用不完整的 sql 语句,空缺的值使用(?)代替,直到执行的时候,再输入进去就可以了。
使用 Statement :
Statement createStatement = conn.createStatement();
int executeUpdate2 = createStatement.executeUpdate("insert into user(name,password) values('1','2')");  
使用 preparedStatement:
//创建预编译语句对象 pstmt = conn.prepareStatement("insert into user(name,password) values(?,?)"); //给4个占位符赋值 pstmt.setString(1, "ww"); pstmt.setString(2, "789"); //执行SQL语句(增加记录) int n = pstmt.executeUpdate();

7,实现对数据库的操作。

package demo;

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Ex01 {
    /**
     * 演示:JDBC访问数据库的操作步骤  查询
     */
    public static void main(String[] args) {

      Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //1、加载驱动程序
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            // 2、通过DriverManager建立数据库连接 Driver 驱动
            String url = "jdbc:mysql://127.0.0.1:3306/test";
            String user = "root";
            String password = "111";
            conn = DriverManager.getConnection(url, user, password);
            // 3.通过Connection获取语句对象Statement (声明)
            stmt = conn.createStatement();
            // 4.使用语句对象执行SQL语句
            rs = stmt.executeQuery("select * from user");
            // 5.遍历结果集
            while (rs.next()) {
                // 取出当前行各个字段的值
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String pwd = rs.getString("password");

                System.out.println(id + " " + name + " " + pwd);
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {// 一定会执行的代码块,无论是否发生异常
            // 6.释放相关资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                rs = null;
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                stmt = null;
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                conn = null;
            }
        }
    }
}
package demo;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

public class Ex02 {
    /**
     * 演示:预编译语句对象PreparedStatemet的使用
     */
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://127.0.0.1:3306/test";
            String user = "root";
            String password = "111";
            conn = DriverManager.getConnection(url, user, password);
            pstmt = conn
                    .prepareStatement("insert into user(name,password,email,birthday) values(?,?,?,?)");
            // 给4个占位符赋值
            pstmt.setString(1, "ww");
            pstmt.setString(2, "789");
            pstmt.setString(3, "ww@qq.com");
            pstmt.setDate(4, Date.valueOf("2016-01-01"));
            // 执行SQL语句(增加记录)
            int n = pstmt.executeUpdate();
            if (n > 0) {
                System.out.println("增加记录成功");
            }
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();
        } finally {

            if (pstmt != null) {

                try {

                    pstmt.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                pstmt = null;            }
            if (conn != null) 
                try {
                    conn.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}
            pstmt = conn.prepareStatement("delete from user where id=?");
            pstmt.setInt(1, id);
            int n = pstmt.executeUpdate();
            if(n>0){
                return true; // 操作成功
            }else{
                return false;  // 操作石板
            }
            pstmt = conn.prepareStatement("update user set name=?,password=?,email=?,birthday=? where id=?");
            pstmt.setString(1, user.getName());
            pstmt.setString(2, user.getPassword());
            pstmt.setString(3, user.getEmail());
            pstmt.setDate(4, user.getBirthday());
            pstmt.setInt(5, user.getId());
            int n = pstmt.executeUpdate();
            if(n>0){
                return true;
            }else{
                return false;
            }

8,JDBC 批处理SQL  

可以使用 Statement  或者 PreparedStatement 对象来实现。
注意:
能够批量处理执行的SQL 必须是 INSTER UPDATE DELETE  等返回 int 类型的SQL。
不能批量执行 SELECT 语句,会进行报错。另外批处理需要数据库的支持,可能有些数据库不支持。
例子一:使用Statement 批处理
package cn.edu.aynu.sushe.utils;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
public class PichuliStatement {
    private static Connection conntection;
    private static Statement statement;
    public static void main(String[] args) {
        try {
            conntection = JDBCUtils.getConntection();
            statement = conntection.createStatement();
            for (int i = 0; i < 10; i++) {
                String sql = "insert into user(name,password) values('a" + i
                        + "','aaa" + i + "')";
                statement.addBatch(sql); // batch 批量
            }
            // 批量执行将每句sql 执行的结果返回为 int【】 数组
            int[] executeBatch = statement.executeBatch(); 
            for (int i = 0; i < executeBatch.length; i++) {
                System.out.println(executeBatch[i] + "");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭流
            if (conntection != null) {
                try {
                    conntection.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            // 关闭流
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }        }
    }
}

数据库:

输出:

1
1
1
1
1
1
1
1
1
1

这个返回的int[]  当数组中的数据出现 大于 0 就代表这条sql 语句被执行成功了。如果小于0 就意味着sql 语句没有执行成功。

例子二:使用PreparedStatement 批处理  

package cn.edu.aynu.sushe.utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class pichuliPreparedStatement { 
    
    public static void main(String[] args) {        
    try {
            Connection conntection = JDBCUtils.getConntection();
            String sql = "insert into user(name,password) values(?,?)";
            PreparedStatement prepareStatement = conntection.prepareStatement(sql);
            
            for (int i = 0; i < 10; i++) {
                int index = 1 ;
                prepareStatement.setString(1, "aa"+i);    
                prepareStatement.setString(2, "aa"+i); 
                prepareStatement.addBatch();
                
            }
            int[] executeBatch = prepareStatement.executeBatch();
            for (int i = 0; i < executeBatch.length; i++) {
                System.out.println(i+"haha");
            }                        
        } catch (Exception e) {
            e.printStackTrace();
        }                
    }
}

数据库输出:

                

处理结果集(针对的就是执行select 语句拿到的ResultSet 对象)

package cn.edu.aynu.sushe.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class ResultSetDemo01 {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Connection conntection;
        try {
            conntection = JDBCUtils.getConntection();
            Statement createStatement = conntection.createStatement(
                    ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_UPDATABLE);
            ResultSet rs = createStatement.executeQuery("select * from user");
            // 光标指向第2行
            rs.absolute(2);
            System.out.println(rs.getInt("id"));
            // 光标向上移动1行
            rs.previous();
            System.out.println(rs.getInt("id"));
            // 光标相对向下移动2行
            rs.relative(2);
            System.out.println(rs.getInt("id"));
            // 光标相对向上移动2行
            rs.relative(-2);
            System.out.println(rs.getInt("id"));
            // 向下移动一行
            rs.next();
            System.out.println(rs.getInt("id"));
        } catch (Exception e) {
            e.printStackTrace();
        }    }
}

 输出:

9,分页显示功能

10,JDBC 高级应用

 DAO 模式  和 JavaBean

DAO (数据库操作对象 DataBase Access  Object)是JDBC 下常用的模式。
保存数据时,将java  bean 的属性拆分成sql语句,并保存到数据库中。
读取数据时,将数据从数据库读出来,通过setXXX方法设置到javabean 中。
看来代码怎么组成:
javabean  对象: (省略  get  set 方法)
package cn.edu.aynu.shuse.bean;
public class Users {
    private int id; // 用户的id,自动增长,作为 linkman 的外键
    private String username; // 用户的姓名
    private String password; // 用户的密码
            getXXX
            setxxx

Dao 类:

package cn.edu.aynu.shuse.dao;

import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import cn.edu.aynu.shuse.bean.Users;
import cn.edu.aynu.shuse.utils.JDBCUtils;
/**
 * 对user表的数据操作,两方面{ (1)根据账户名,去查找密码 (2)注册添加用户的信息 }
 * 
 * @author Administrator
 * 
 */
public class UsersDao {
    /**
     * QueryRunner类简化了执行SQL语句的代码,它与ResultSetHandler组合在一起就能完成大部分的数据库操作,大大减少编码量。
     * 针对不同的数据库操作,QueryRunner类提供的不同的方法。
     */
    QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
    /**
     * (1)根据账户名,去查找密码 
     * 
     * @throws SQLException
     */
    public Users select(String name) throws SQLException {
        String sql = "select * from user where username=?";
        Users list = qr.query(sql, new BeanHandler<Users>(Users.class), name);
        return list;
    }
    /**
     * (2)注册添加用户的信息
     * 
     * @throws SQLException
     */
    public void add(String name, String password) throws SQLException {
        String sql = "insert into user(username,password) values(?,?) ";
        qr.update(sql, name, password);
    }
}

11,JDBC 数据库连接池

为什么需要使用数据库连接池?

在JDBC编程中,每次创建和断开Connection对象都会消耗一定的时间和IO资源
频繁地创建、断开数据库连接势必会影响数据库的访问效率,甚至导致数据库崩溃。
为了避免频繁的创建数据库连接,工程师们提出了数据库连接池技术。

什么是数据库连接池?

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用现有的数据库连接,而不是重新建立。

怎么使用数据库连接池?

【1】获取数据库连接(Connection)

既然要连接数据库就应该获取数据库连接对象(Connection),那么我们通过使用JDBC提供了javax.sql.DataSource接口
(它负责与数据库建立连接,并定义了返回值为Connection对象的方法) Connection getConnection() Connection getConnection(String username,String password) 来拿到我们的数据库连接对象

【2】获取数据库连接池对象(DataSource)

我们习惯性的把实现了javax.sql.DataSource接口的类称为数据源,顾名思义,数据源即数据的来源

在数据源中存储了所有建立数据库连接的信息

常用的数据源分为两种 :
1,DBCP  
2,C3P0
DBCP数据库连接池(DataBase Connection Pool)的简称,是Apache组织下的开源连接池实现,也是Tomcat服务器使用的连接池组件单独使用DBCP数据源时,需要在应用程序中导入两个jar包。commons-pool.jar包  commons-dbcp.jar包
(commons-dbcp.jar包中包含两个核心类,分别是BasicDataSourceFactoryBasicDataSource,它们都包含获取DBCP数据源对象的方法。)

C3P0是目前最流行的开源数据库连接池之一,它实现了DataSource数据源接口,支持JDBC2和JDBC3的标准规范,易于扩展并且性能优越,
著名的开源框架Hibernate和 Spring使用的都是该数据源。 需要了解C3P0中DataSource接口的实现类ComboPooledDataSource,它是C3P0的核心类,提供了数据源对象的相关方法

【3】使用DBCP 数据源 获取数据库的连接

当使用DBCP数据源时,首先得创建数据源对象,数据源对象的创建方式有两种

第一种通过BasicDataSource直接创建数据源对象手动给数据源对象设置属性值然后获取数据库连接对象第二种通过读取配置文件创建数据源对象使用BasicDataSourceFactory工厂类读取配置文件创建数据源对象然后获取数据库连接对象。(推荐使用)

第一种方式:类创建

package cn.edu.aynu.DBCP;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
public class leichuangjian {
        public static DataSource  ds = null ;
    static {
        // 获取DBCP的数据源对象
        BasicDataSource basicDataSource = new BasicDataSource();
        /*
         * 【1】设置数据库的配置信息
         */
        // 设置连接数据库的驱动名称        
basicDataSource.setDriverClassName("com.mysql.jdbc.Driver"); // 设置连接数据库的路径 basicDataSource.setUrl("jdbc:mysql://localhost:3306/test"); // 设置数据库的登陆账号 basicDataSource.setUsername("root"); // 设置数据库的登录密码 basicDataSource.setPassword("111"); /* * 【2】设置数据库连接池的信息 * */ //设置数据库连接池初始化的连接数目 basicDataSource.setInitialSize(10); //设置数据库连接池最大活跃的连接数目 basicDataSource.setMaxActive(5); //设置数据库连接池最小闲置的连接数目 basicDataSource.setMinIdle(2); ds = basicDataSource; } /** * @param args * @throws SQLException */ public static void main(String[] args) throws SQLException { // 导入jar包 // 从数据库获取一个连接 Connection connection = ds.getConnection(); System.out.println(connection); } }
第二种:使用配置文件进行创建

注意:这个配置文件 后缀必须是 : xxx.properties 否者创建的就是错误的

package cn.edu.aynu.DBCP;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public class peizhichuangjian {
    /**
     * @param args
     * @throws Exception
     */
    @SuppressWarnings("static-access")
    public static void main(String[] args) throws Exception {
        // 通过配置文件来返回数据库的连接
        Properties properties = new Properties();
        // 通过类加载器拿到配置信息
        InputStream inputStream = new peizhichuangjian()//
                .getClass()//
                .getClassLoader()//
                .getSystemResourceAsStream("ds.properties");
        // 加载拿到的流
        properties.load(inputStream);
        // 通过工厂类创建DataSourse
        DataSource createDataSource = BasicDataSourceFactory
                .createDataSource(properties);
        Connection connection = createDataSource.getConnection();
        System.out.println(connection);
    }
}

【4】使用C3P0 数据源 获取数据库的连接

 当使用C3P0数据源时,首先得创建数据源对象,数据源对象的创建方式有两种。

第一种通过ComboPooledDataSource类直接创建数据源对象手动给数据源对象设置属性值然后获取数据库连接对象第二种通过读取配置文件创建数据源对象使用ComboPooledDataSource读取配置文件,创建数据源对象,然后获取数据库连接对象。(推荐使用)
其中读取配置文件,有两种方式一种是默认的一种是自定义的详情看下面)

一,类创建:

package cn.edu.aynu.C3P0;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class leichuangjian {
    public static DataSource ds = null;
    static {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        // 【1】配置数据源的信息
        try {
            comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");
            comboPooledDataSource
                    .setJdbcUrl("jdbc:mysql://127.0.0.1:3306/test");
            comboPooledDataSource.setUser("root");
            comboPooledDataSource.setPassword("111");
            // 设置连接池信息
            comboPooledDataSource.setInitialPoolSize(10);
            comboPooledDataSource.setMaxPoolSize(100);
            ds = comboPooledDataSource;
        } catch (PropertyVetoException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    /**
     * @param args
     * @throws SQLException 
     */
    public static void main(String[] args) throws SQLException {
        Connection connection = ds.getConnection();
        System.out.println(connection);        
    }
}

二,使用配置文件进行创建:

以xml 的方式进行的存储 这个文件存放在 src 目录下

 

其中的配置代码:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!-- 默认配置,当使用ComboPooledDataSource无参构造器时,使用的就是这个配置 -->
    <default-config>
        <!-- 基本配置 -->
        <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/test</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="user">root</property>
        <property name="password">111</property>
        <!-- 每次增量,当需要创建Connection对象时,一次创建几个 -->
        <property name="acquireIncrement">3</property>
        <!-- 当创建池对象后,池中应该有几个Connection对象 -->
        <property name="initialPoolSize">10</property>
        <!-- 池中最少Connection个数,如果少于这个值,就会创建Connection -->
        <property name="minPoolSize">2</property>
        <!-- 池中最大连接个数 -->
        <property name="maxPoolSize">10</property>
    </default-config>
    <!-- 命名配置,new ComboPooledDataSource("oralce-config")时,使用的就是这个配置 -->
    <named-config name="mysql-config">
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="user">root</property>
        <property name="password">111</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>

获取数据源:

package cn.edu.aynu.C3P0;

import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class morenpeizhi {
    public static DataSource ds = null;
    
    static{
        // 使用默认的配置
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        ds =comboPooledDataSource;
        // 使用mysql-config 命名的文件创建
        ComboPooledDataSource comboPooledDataSource  = new ComboPooledDataSource("mysql-config");
        ds =comboPooledDataSource ;
    }    
    /**
     * @param args
     * @throws SQLException 
     */
    public static void main(String[] args) throws SQLException {
        Connection connection = ds.getConnection();  // 拿到连接
        System.out.println(connection);        
    }
}

12,事务实例: 银行转账(经典题目)

如何使用JDBC处理事务?

1)在数据库操作中,一项事务由一条或多条操作数据库的SQL语句组成的一个不可分割的工作单元2)只有当事务中的所有操作都正常完成整个事务才能被提交到数据库中,如果有一项操作没有完成,则整个事务会被撤销
 例如 银行的转账业务 

通过 Connection 接口中提供了三个方法来针对 JDBC 处理事物。

其中有三个方法:
setAutoCommit(boolean autoCommit)// 设置自动提交 我们需要将这个方法设置为 false 不自动提交
//开启事务
    public static void startTransaction(){
        try {
            //获取连接
            Connection conn = getConnection();
            //开启事务
            conn.setAutoCommit(false);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }        
    }
commit() // 提交   当我们的事务完成的时候,提交
//提交事务
    public static void commit(){
        try {
            //从集合tc中得到一个连接
            Connection conn = tc.get();
            if(conn != null){
                conn.commit();
            }            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

rollback()  // 回滚  当我们的事务出现异常的时候,回滚

//回滚事务
    public static void rollback(){
        try {
            //从集合tc中得到一个连接
            Connection conn = tc.get();
            if(conn != null){
                conn.rollback();
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

银行转账的业务逻辑

用户 zs 要向 ls 的账户上转200 元钱,该转账业务需要分成两步:
第一步:zs 的账户上需要减少 200 元钱
第二步:ls 的账户上需要增加 200 元钱
这两步操作需要都成功,事务才成功。也就是说,要么都执行成功,要么都没有执行成功。 那么就会出现两种结果,一种是commit() 执行成功,要么就需要执行 rollback () ;

13,介绍ThreadLocaL类

为什么使用ThreadLocaL 类?
Web应用程序,多用户并发访问。
一个客户端访问时,服务器启动一个线程,比如转账,在这个线程中独立完成这个事务操作,
另外一个客户端也来访问时,服务器也启动另外一个线程,在另外一个线程中独立完成转账事务操作。 要想多线程中每个事务执行成功必须保证每个线程有独立的Connection对象
ThreadLocaL类介绍:
ThreadLocaL类:在一个线程中记录本地变量。
我们可以将一个Connection对象放到这个ThreadLocaL集合中,只要是这个线程中的对象都可以共享这个Connection对象线程结束后删除这个Connection对象
这样保证:一个事务一个连接。

TreadLoacl本质上是一个Map,键是当前线程对象,值可以是我们的当前连接对象。

    //创建一个ThreadLoacl对象,用当前线程作为key
    private static ThreadLocal<Connection> tc = new ThreadLocal<Connection>();

14,实例

在使用数据源(DataSource )时,如果是业务处理,使用C3P0 时,不需要拿数据源对象。

Java Web应用开发的三层架构:
1、表示层(Web层):jsp和servlet
2、业务逻辑层(Service层):XXXService,事务操作是在service层完成的。
3、数据访问层(dao层):XXXDao
按照编写正常代码演示:
bean-->Utils ---> Dao--->service--->Servlet
先看下数据库表:
test数据库中 account 表三个字段:  id 主键自动递增,name 姓名 , money 账户的金额 (double 类型)

 Account.java

package cn.edu.aynu.rjxy.bean;
public class Account {

    private int id;
    private String name;
    private double money;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getMoney() {
        return money;
    }
    public void setMoney(double money) {
        this.money = money;
    }
}

JDBCUtils.java

package cn.edu.aynu.rjxy.utils;

import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JDBCUtils {
    //创建一个ThreadLoacl对象,用当前线程作为key
    private static ThreadLocal<Connection> tc = new ThreadLocal<Connection>();
    //从c3p0-config.xml文件中读取默认配置创建数据库连接池对象
    private static DataSource ds = new ComboPooledDataSource();

    //得到数据库连接池对象
    public static DataSource getDataSource(){
        return ds;
    }
    
    //从连接池中获取连接
    public static Connection getConnection() throws Exception{
        //从集合tc中获取一个Connection
        Connection conn = tc.get();
        if(conn == null){
            conn = ds.getConnection();
            //将conn存放到集合tc中
            tc.set(conn);
            System.out.println("首次创建连接:"+conn);
        }
        return conn;
    }

    //开启事务
    public static void startTransaction(){
        try {
            //获取连接
            Connection conn = getConnection();
            //开启事务
            conn.setAutoCommit(false);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    
    }
    //提交事务
    public static void commit(){
        try {
            //从集合tc中得到一个连接
            Connection conn = tc.get();
            if(conn != null){
                conn.commit();
            }            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }        
    }
    
    //回滚事务
    public static void rollback(){
        try {
            //从集合tc中得到一个连接
            Connection conn = tc.get();
            if(conn != null){
                conn.rollback();

            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    //关闭连接释放资源
    public static void close(){
        //从集合tc中得到一个连接
        Connection conn = tc.get();
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally{
                //从集合tc中移除连接对象
                tc.remove();
                conn = null;
            }
        }
    }
}

AccountDao,java

package cn.edu.aynu.rjxy.dao;

import java.sql.Connection;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import cn.edu.aynu.rjxy.bean.Account;
import cn.edu.aynu.rjxy.utils.JDBCUtils;

public class AccountDao {
    //根据账户名查询账户信息
    public Account find(String name) throws Exception{
        QueryRunner run = new QueryRunner();   // 处理事务,不需要传 数据源对象
        Connection conn = JDBCUtils.getConnection();
        System.out.println("find()得到连接:"+conn);
        String sql = "select * from account where name=?";
        Account account  = (Account)run.query(conn, sql, new BeanHandler(Account.class), new Object[]{name});    
        return account;        
    }
    
    //转账(可能转入也可能转出)
    public void update(Account account) throws Exception {
        QueryRunner run = new QueryRunner();
        Connection conn = JDBCUtils.getConnection();
        System.out.println("update()得到连接:"+conn);
        String sql = "update account set money=? where name=?";
        run.update(conn, sql, new Object[]{account.getMoney(),account.getName()});
    }
}

AccountService.java  转账的业务逻辑

package cn.edu.aynu.rjxy.service;
import cn.edu.aynu.rjxy.bean.Account;
import cn.edu.aynu.rjxy.dao.AccountDao;
import cn.edu.aynu.rjxy.utils.JDBCUtils;
public class AccountService {
    //转账事务
    public static void transfer(String fromName,String toName,double balance){
        try {
            //开启事务
            JDBCUtils.startTransaction();
            AccountDao dao = new AccountDao();
            //查询两个账户的金额
            Account accountFrom = dao.find(fromName);
            Account accountTo = dao.find(toName);
            //判断是否可以转账
            if(balance<accountFrom.getMoney()){
                //可以转账
                //设置转出账户的金额
                accountFrom.setMoney(accountFrom.getMoney()-balance);
                //设置转入账户的金额
                accountTo.setMoney(accountTo.getMoney()+balance);
                //执行数据库更改操作
                dao.update(accountFrom); 
                dao.update(accountTo);
                //提交事务
                JDBCUtils.commit();
                System.out.println("事务提交成功");
            }else{
                System.out.println("转出账户金额不足");
            }
            
        } catch (Exception e) {
            //回滚事务
            JDBCUtils.rollback();
            System.out.println("事务提交失败");
            e.printStackTrace();
        }finally{
            //释放资源
            JDBCUtils.close();
        }
    }
}
测试转账是否能够完成
import cn.edu.aynu.rjxy.service.AccountService;
public class TestTransfer {
    /**
     * @param args
     */
    public static void main(String[] args) {
        //实现从zs账户上转账200到ls账户上
        AccountService.transfer("zs", "ls", 200);
    }
}
源码:https://github.com/gengzi/files/tree/master/%E9%93%B6%E8%A1%8C%E8%BD%AC%E8%B4%A6%EF%BC%88%E6%A1%88%E4%BE%8B%EF%BC%89
数据库:https://github.com/gengzi/files/tree/master/%E9%93%B6%E8%A1%8C%E8%BD%AC%E8%B4%A6%EF%BC%88%E6%A1%88%E4%BE%8B%EF%BC%89

 

 
    

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM