DButils

三层架构和Apache的DbUtils

回顾

1 封装数据库工具类
	四个基本功能 (1)加载驱动 (2) 获取连接 (3) 释放连接 (4) 执行命令   (String sql,Object...params)
2 封装查询数据
	把数据库中数据封装成实体对象
3 DAO模式
	把数据库操作封装起来,把业务逻辑代码和数据访问代码隔离开。职责分离,降低耦合性
	四个部分 1 DAO接口  2 DAO实现类 3 实体类  4 数据库工具类
4 连接池
	Druid连接池的使用

今日内容

1、三层架构
2、JDBC控制事务
3、三层实现事务
4、ThreadLocal类使用
5、Apache的DbUtils工具类使用

教学目标

1、理解三层架构
2、理解JDBC控制事务
3、掌握三层实现事务
4、掌握ThreadLocal类
5、Apache的DBUtils工具类

第一节 三层架构

DAO模式的缺点

	DAO模式仅仅提供了对数据访问的操作,业务逻辑代码和负责展示的代码是耦合在一起的,所以需要把业务代码和负责展示的代码分离开就出现了三层架构。
1.1 什么是三层架构

三层架构(3-tier architecture) 就是将整个业务应用划分为:界面(表示)层(User Interface layer)、业务逻辑层(Business Logic Layer)、数据访问层(Data Access Layer)。区分层次的目的即为了高内聚低耦合的思想。

每层功能

1、数据访问层:是对数据库的基本操作(增删改查等),具体为业务逻辑层提供数据服务。

2、业务逻辑层:主要是针对具体的问题的操作,对数据业务逻辑处理,比如注册、转账等。

3、界面(表示)层:主要界面方式有WEB或Window窗口、控制台等,负责向用户展现特定业务数据、采集用户的输入信息和操作。

1.2 引用关系

表示层调用业务逻辑层,业务逻辑层调用数据访问层。下层为上层提供服务。上层调用下层。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gv2g9jGu-1678337197881)(pic\三层.png)]

1.3 分层优缺点

优点:

(1)有助于分层开发

(2)无损替换

(3)降低层与层之间的依赖

(4)提高代码的重用性

缺点:

(1)增加开发成本

(2)降低系统性能

1.4 业务层(service)

什么是业务?

​ 代表用户完成的一个业务功能,可以由一个或多个DAO的调用组成。(软件所提供的一个功能都叫业务)

转账:一次转账。两个DAO操作:扣钱,加钱

在DAO模式基础上添加service层,service层的包命名规则

接口包名:service
	接口名:xxxService
实现类包名:impl
	实现类:xxxServiceImpl

三层架构演示

业务层Service接口代码:

package com.qf.www.service;
/*
	service层是业务层,是个接口,业务中方法名可以和DAO中方法相同,也可以不相同
*/
public interface EmpService {
    //1查询
    List<Emp> findAll();
    //2更新
    void update(Emp e);
    //3删除
    void delete(int empno);
    //4添加
    void add(Emp e);
}

业务层service实现类代码

package com.qf.www.service.impl;

import com.qf.www.service.EmpService;
/*
	业务层实现类主要是创建DAO层的数据访问对象,然后调用方法完成业务功能
*/
public class EmpServiceImpl implements EmpService {
    private EmpDao empDao = new EmpDaoImpl();
    @Override
    public List<Emp> findAll() {
        List<Emp> list = empDao.findAll();
        return list;
    }

    @Override
    public void update(Emp e) {
		empDao.update(e);
    }

    @Override
    public void delete(int empno) {
			empDao.delete(empno);
    }

    @Override
    public void add(Emp e) {
		empDao.add(e);
    }
}

第二节 JDBC控制事务

回顾:

事务是由完成任务的一个或多个操作组成,这些操作作为一个整体不能分割,要么全部执行成功,要么全部失败。

事务四个特性:

原子性(Atomicity,或称不可分割性)
一致性(Consistency)
隔离性(Isolation,又称独立性)
持久性(Durability)

MySQL中与事务控制有关的SQL语句:

BEGIN或START TRANSACTION;开启事务
COMMIT;提交事务
ROLLBACK;回滚事务

在JDBC中实现事务控制需要使用Connection对象提供的方法

conn.setAutoCommit(false);开启事务
conn.commit();提交事务
conn.rollback();回滚事务

案例实现:使用事务实现转账

(1)准备表

CREATE TABLE account(
	`id` INT PRIMARY KEY,
	`name` VARCHAR(20) NOT NULL,
	`money` DOUBLE(10,2)
)
  

(2)代码实现

public static void main(String[] args) {
		Connection connection=null;
		PreparedStatement pstat1=null;
		PreparedStatement pstat2=null;
		
		//1注册驱动
		try {
			Class.forName("com.mysql.jdbc.Driver");
			//2获取连接
			connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root");
			//3创建命令
			//3.1开启事务 ,设置事务自动提交为false
			connection.setAutoCommit(false);
			pstat1=connection.prepareStatement("update account set money=money-1000 where name='张莎强'");
			pstat1.executeUpdate();
			//int c=10/0;
			pstat2=connection.prepareStatement("update account set money=money+1000 where name='小苍'");
			pstat2.executeUpdate();
			
			System.out.println("转账成功...");
			//3.2提交事务
			connection.commit();
			
		} catch (Exception e) {
			System.out.println("出现异常");
			try {
				connection.rollback();//出现问题,要回滚(撤销事务做过的修改)
				connection.commit();//可加也不不加
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}finally {
				try {
                    if(pstat1!=null)
					pstat1.close();
                    if(pstat2!=null)
                    pstat2.close();     
                    if(connection!=null)
                    connection.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

第三节 三层实现事务

3.1项目准备

​ 创建Java项目

​ 导入需要的jar包 mysql驱动、 druid.jar

​ 添加数据库配置文件

  • db.properties
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/account
username=root
password=1234
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=5000
3.2编写Java代码

应用三层架构,其中dao层,我们已经搭建过,只需要添加service业务层和view视图层

3.2.1包结构
com.qf.dao

​ com.qf.dao.impl

​ com.qf.service

​ com.qf.service.impl

​ com.qf.view

​ com.qf.utils

​ com.qf.domain

3.2.2编写DbUtils工具类

DBUtils工具类,优化获取连接,优化事务操作

package com.itqf.utils;

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

import javax.sql.DataSource;

import com.qf.utils.DruidUtils;

public class DbUtils {
	private static DruidDataSource ds=null;
   //静态代码块
    static {
        InputStream is = DruidUtils.class.getClassLoader().getResourceAsStream("db.properties");
        Properties properties=new Properties();
        try {
            properties.load(is);
            dataSource= (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
	/**
	 * 获取数据源
	 * @return 连接池
	 */
	public static DataSource getDataSource(){
		return ds;
	}
	
	/**
	 * 从当前线程上获取连接
	 * @return 连接
	 * @throws SQLException
	 */
	public static Connection getConnection() throws SQLException{
		//--从
		try {
            Connection connection = ds.getConnection();
            return connection;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
	}
 //关闭
    public static void close(){
        Connection connection = getConnection();
        try {
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
	/**
	 *---- 开启事务
	 * @throws SQLException
	 */
	public static void startTransaction() throws SQLException{
		//获取连接//开启事务
		getConnection().setAutoCommit(false);
	}
	
	/**
	 *--- 事务提交
	 */
	public static void commitAndClose(){
		try {
			//获取连接
			Connection conn = getConnection();
			//提交事务
			conn.commit();
			//释放资源
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * ----事务回滚
	 */
	public static void rollbackAndClose(){
		try {
			//获取连接
			Connection conn = getConnection();
			//事务回滚
			conn.rollback();
			//释放资源
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
3.2.3编写DAO层代码

DAO层进行具体数据库操作

实体类:

package com.qf.www.entity;

public class Account {
    private int id;
    private String name;
    private double money;

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + 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;
    }

    public Account() {
    }

    public Account(int id, String name, double money) {
        this.id = id;
        this.name = name;
        this.money = money;
    }
}
package com.qf.www.dao.impl;

import com.qf.www.dao.AccountDao;
import com.qf.www.utils.DBUtils;
import org.apache.commons.dbutils.QueryRunner;

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

public class AccountDaoImpl implements AccountDao {
    private Connection connection = null;
    private PreparedStatement preparedStatement = null;
    private ResultSet resultSet = null;
    @Override
    public void updateSave(int cardNo, double money) {
        connection = DBUtils.getConnection();
        String sql = "update account set money = money+? where id = ?";
        try {
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setDouble(1, money);
            preparedStatement.setInt(2, cardNo);
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtils.close();
        }
    }

    @Override
    public void updateTake(int cardNo, double money) {
        connection = DBUtils.getConnection();
        String sql = "update account set money = money-? where id = ?";
        try {
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setDouble(1, money);
            preparedStatement.setInt(2, cardNo);
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtils.close();
        }
    }
}

3.2.4编写业务层代码
package com.itqf.service;

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

import com.itqf.dao.AccountDao;
import com.itqf.dao.AccountDaoDButis;
import com.itqf.dao.AccountDaoLocal;
import com.itqf.utils.DataSourceUtils;
import com.itqf.utils.JdbcUtils;
/**
 * jdbc+threadlocal
 * 
 * @author Administrator
 *
 */
public class AccountServiceImpl {
    
	/**
	 * 转账业务逻辑
	 * @param from
	 * @param to
	 * @param money
	 * @throws Exception 
	 */
	public  void transfer(int from, int to,double money) throws Exception {
		AccountDaoDButis accountDao = new AccountDaoDButis();
		try {
			//开启事务
			DataSourceUtils.startTransaction();
			//1.转出
			accountDao.out(from,money);
			//2.转入
			accountDao.in(to,money);
			DataSourceUtils.commitAndClose();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace
			DataSourceUtils.rollbackAndClose();
			throw e; //接着向外抛
		}
	}

}
3.2.4编写视图层代码

视图层主要用于用户输入转账内容,调用业务层

package com.qf.www.view;

import com.qf.www.service.AccountService;
import com.qf.www.service.impl.AccountServiceImpl;

import java.util.Scanner;

public class StartView {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("欢迎登陆转账系统:");
        System.out.println("请输入卡号:");
        int from  = scanner.nextInt();
        System.out.println("请输入对方卡号");
        int to = scanner.nextInt();
        System.out.println("请输入转账金额");
        double money = scanner.nextDouble();
        //调用业务层
        AccountService accountService = new AccountServiceImpl();
        //调用转账方法,传入参数
        accountService.transfer(from, to, money);
    }
}

第四节 ThreadLocal类

三层结合事务现存在的问题:

当前事务出现异常,一个DAO操作执行成功,一个DAO失败,则需要进行回滚,但是却发现回滚失败了,原因是在整个事务操作过程中,每一个环节应用的数据库连接对象都不是同一个,所以事务的控制从头到尾不是一个连接。

需要使用ThreadLocal, 可以在整个线程(单条执行路径)所持有的Map中,存储一个键值,值是与当前线程关联的Connection对象,只要保证线程是同一个,则获取到的Connection是同一个。

4.1优化DbUtils
package com.itqf.utils;

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

import javax.sql.DataSource;

import com.qf.utils.DruidUtils;

public class DbUtils {
	private static DruidDataSource ds=null;
    //创建
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
   //静态代码块
    static {
        InputStream is = DruidUtils.class.getClassLoader().getResourceAsStream("db.properties");
        Properties properties=new Properties();
        try {
            properties.load(is);
            dataSource= (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
	/**
	 * 获取数据源
	 * @return 连接池
	 */
	public static DataSource getDataSource(){
		return ds;
	}
	
	/**
	 * 从当前线程上获取连接
	 * @return 连接
	 * @throws SQLException
	 */
	public static Connection getConnection() throws SQLException{
		try {
           //--从线程获取链接
            Connection connection = threadLocal.get();
            if(connection==null){
                //第一次获取 创建一个连接 和当前的线程绑定
                connection = ds.getConnection();
                	 //----绑定
                threadLocal.set(connection);
            }
            return connection;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
	}
 //关闭
    public static void close(){
        Connection connection = getConnection();
        try {
            //和当前线程解绑
            threadLocal.remove();
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
	/**
	 *---- 开启事务
	 * @throws SQLException
	 */
	public static void startTransaction() throws SQLException{
		//获取连接//开启事务
		getConnection().setAutoCommit(false);
	}
	
	/**
	 *--- 事务提交
	 */
	public static void commitAndClose(){
		try {
			//获取连接
			Connection conn = getConnection();
			//提交事务
			conn.commit();
			//释放资源
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * ----事务回滚
	 */
	public static void rollbackAndClose(){
		try {
			//获取连接
			Connection conn = getConnection();
			//事务回滚
			conn.rollback();
			//释放资源
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
4.2优化DAO层代码
package com.qf.www.dao.impl;

import com.qf.www.dao.AccountDao;
import com.qf.www.utils.DBUtils;
import org.apache.commons.dbutils.QueryRunner;

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

public class AccountDaoImpl implements AccountDao {
    private Connection connection = null;
    private PreparedStatement preparedStatement = null;
    private ResultSet resultSet = null;
    @Override
    public void updateSave(int cardNo, double money) {
        connection = DBUtils.getConnection();
        String sql = "update account set money = money+? where id = ?";
        try {
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setDouble(1, money);
            preparedStatement.setInt(2, cardNo);
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
//            DBUtils.close();不在dao调用关闭连接的方法!
        }
    }

    @Override
    public void updateTake(int cardNo, double money) {
        connection = DBUtils.getConnection();
        String sql = "update account set money = money-? where id = ?";
        try {
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setDouble(1, money);
            preparedStatement.setInt(2, cardNo);
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
//            DBUtils.close();不在dao调用关闭连接的方法!
        }
    }
}

第五节 Apache的DbUtils使用

Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。

下载地址:http://commons.apache.org/proper/commons-dbutils/download_dbutils.cgi

5.1 DbUtils简介

DbUtils是java编程中的数据库操作实用工具,小巧简单实用。

功能:

1.对于数据表的读操作,可以把结果转换成List,Array,Set等java集合,便于程序员操作。

2.对于数据表的写操作,也变得很简单(只需写sql语句)。

DbUtils包括主要类

DbUtils类:启动类

ResultSetHandler接口:转换类型接口

​ –ScalarHandler类:适合获取一行一列数据。

​ –BeanHandler类:实现类,把记录转成对象。

​ –BeanListHandler类:实现类,把记录转化成List,使记录为JavaBean类型的对象

​ --ArrayHandler类:实现类,把记录转化成数组

​ --ArrayListHandler类:把记录转化成数组,并放入集合中

​ --ColumnListHandler类:取某一列的数据。封装到List中。

QueryRunner类:执行SQL语句的类

5.2 DbUtils使用步骤
5.2.1 项目准备
  • 创建项目
  • 导入jar包 、配置文件
    MySQL驱动包
    commons-dbutils-1.6.jar
    druid-1.1.5.jar
    druid.properties配置文件
5.2.2 创建数据源工具类

由于Apache的DBUtils工具需要一个数据源对象,所以需要创建工具类返回数据源对象

DruidUtils.java

public class DruidUtils {
    private static DruidDataSource dataSource;
    static {
        try {
            Properties properties=new Properties();
            InputStream is=DataSourceUtils.class.getClassLoader().getResourceAsStream("druid.properties");
            properties.load(is);

            dataSource= (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static DataSource getDataSource(){
        return dataSource;
    }
}
5.2.3 实现代码
public class ResultHanlderTest {
	@Test
	public void testBeanHandler() throws SQLException {
		// BeanHandler:适合取单行单列数据
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());
		Employee query = runner.query("select * from emp where empno=1234 ", new BeanHandler<Employee>(Employee.class));
		System.out.println(query.toString());
	}
  
  	@Test
	public void testBeanListHandler() throws SQLException {
		// BeanHandler:适合取多行多列数据
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());
		List<Employee> query2 = runner.query("select * from emp", new BeanListHandler<Employee>(Employee.class));
		for (Employee employee : query2) {
			System.out.println(employee);
		}
	}
    @Test
	public void testScalarHandler() throws SQLException {

		// ScalarHandler:适合取单行单列数据
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());

		Object query = runner.query("select count(*) from emp ", new ScalarHandler());
		System.out.println(query);
	}
	@Test
	public void testArrayHander() throws SQLException {

		// ArrayHandler:适合取1条记录。把该条记录的每列值封装到一个数组中Object[]
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());

		Object[] query = runner.query("select * from school where empno = ?", new ArrayHandler(), 1234);

		for (Object object : query) {

			System.out.println(object);
		}

	}

	@Test
	public void testArrayListHander() throws SQLException {

		// ArrayHandler:适合取1条记录。把该条记录的每列值封装到一个数组中Object[]
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());

		List<Object[]> query = runner.query("select * from emp ", new ArrayListHandler());

		for (Object[] objects : query) {
			for (Object object : objects) {

				System.out.println(object);
			}
		}

	}

	@Test
	public void testColumnListHander() throws SQLException {

		// ColumnListHandler:取某一列的数据。封装到List中。
		QueryRunner runner = new QueryRunner(DruidUtils.getDataSource());

		List<Object> query = runner.query("select * from emp ", new ColumnListHandler<Object>(2));

		for (Object objects : query) {

			System.out.println(objects);

第六节 封装查询方法(扩展)

6.1 RowMapper接口方式

步骤1 定义封装规则接口

RowMapper接口

import java.sql.ResultSet;
//封装规则。封装对象为泛型,通用。参数需要的是ResultSet对象
public interface RowMapper<T> {
    T getRow(ResultSet rs);
}

步骤2 DbUtils中增加查询方法

//查询通用方法 泛型方法。返回值为泛型集合,因为查询可能是单个或多个
//参数:sql语句、封装方式、参数列表
    public static <T> List<T> executeQuery(String sql , RowMapper<T> mapper,Object... params){
        PreparedStatement preparedStatement = null;
        Connection connection = getConnection();
        ResultSet rs = null;
        //定义泛型集合,类型由封装方式的具体对象来决定
        List<T> list=new ArrayList<T>();
        try {
            preparedStatement = connection.prepareStatement(sql);
            //循环为占位符赋值
            for(int i= 0;i<params.length;i++){
                preparedStatement.setObject(i+1, params[i]);
            }
            rs = preparedStatement.executeQuery();
            //迭代
            while(rs.next()){
                //获得一行数据,调用封装方式,得到对象,添加到集合中
                list.add(mapper.getRow(rs));
            }
            return list;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            closeAll(rs, preparedStatement, connection);
        }	
        return null;
    }

步骤3:编写接口实现类

import java.sql.ResultSet;
import java.sql.SQLException;
//定义具体的封装方式,决定通用查询封装的是具体某个对象
//遍历ResultSet,取值做对象属性的赋值
public class AccountRowMapper implements RowMapper<Account> {
    @Override
    public Account getRow(ResultSet rs) {
        Account account = new Account();
        try {
            account.setId(rs.getInt(1));
            account.setName(rs.getName(2));
            account.setMoney(rs.getDouble(3));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return account;
    }
}
6.2 反射方式

通用性更强,理解即可

 //返回List集合的方法
    public  static <T> List<T> executeQuery(String sql,  Class<T> class1,Object... params){
        List<T> list=new ArrayList<>();
        Connection conn=null;
        PreparedStatement pstat=null;
        ResultSet rs=null;
        //查询数据
        try {
            conn=getConnection();
            pstat = conn.prepareStatement(sql);
            if(params!=null){
                for (int i = 0; i < params.length; i++) {
                    pstat.setObject(i+1, params[i]);
                }
            }
            rs = pstat.executeQuery();
            //获取rs中的列名
            ResultSetMetaData metaData = rs.getMetaData();
            while(rs.next()){
                //创建一个对象
              	 T t=class1.newInstance();
                 for(int i=0;i<metaData.getColumnCount();i++){
                 	 String columnLabel=metaData.getColumnLabel(i+1);
                 	 Object value = rs.getObject(columnLabel);//empno  ename job
                     //System.out.println(columnLabel+"==="+value);
                     //创建属性描述符
                	 try {
                 		 PropertyDescriptor pd=new PropertyDescriptor(columnLabel, class1);
                 		 if(pd!=null){
                		    //System.out.println(pd.getName());
                 		    Method writeMethod = pd.getWriteMethod(); //setEmpno setEname setJob
                		    writeMethod.invoke(t,value);
                 	     }
                      } catch (Exception e) {
                		 continue;
                      }
                 }	
                list.add(t);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            closeAll(conn, pstat, rs);
        }
        return list;
    }

总结

1、三层架构 DAO、Service、UI Utils 工具类 domain实体类

2、JDBC操作事务,结合事务的三层架构,在DBUtils工具类里,封装对事务的一系列操作

3、ThreadLocal解决多个DAO操作,connection对象不同步的问题。

4、Apache DBUtils的使用,QueryRunner ResultSetHanlder 接口

5、扩展理解

作业题

1、使用三层架构重构学生管理系统,要求实现正删改查,基于控制台实现即可
要求可以对学生信息进行添加、修改、删除、查询的功能

面试题

1、什么三层架构?
2、JDBC事务控制方法有那些
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值