JDBC知识回顾
DAO封装
ThreadLocal
JDBC及DAO综合运用
1.JDBC
2.ODBC与JDBC
3.JDBC的四种驱动类型
JDBC-ODBC桥加ODBC驱动
本地API驱动
网络协议驱动
本地协议驱动
4.Connection,Statement,ResultSet
5.事务,并发控制
6.行集
7.连接池
8.对象关系映射
9.应用程序架构
三层(多层):显示层,业务逻辑层,数据层
数据访问代码属于业务逻辑层
业务逻辑通过操作数据实现相关功能
1.DAO
Data Access Object—数据访问对象
访问数据库,操作数据的代码
建立数据库连接,操作数据库数据
2.DAO封装
将数据访问代码封装为一个组件,与业务逻辑代码隔开
使数据访问与业务逻辑分离,业务逻辑不需要关心数据操作
应用程序结构清晰,易于维护和扩展,方便的改变数据库及配置
是访问数据的相关技术的综合运用
JDBC,Connection,Statement ,ResultSet
事务,并发控制,连接池,行集,ThreadLocal
对象关系映射,多层架构
1.问题
多线程访问数据时,每个线程在多个地方要用到连接,难以管理
每个线程打开多个连接对象,浪费资源
2.ThreadLocal
java.lang.ThreadLocal
为解决多线程程序的并发问题提供了一种新的思路
当使用ThreadLocal维护对象时,ThreadLocal为每个使用该对象的线程提供独立的对象副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
使用ThreadLocal管理每个线程使用的连接对象
唯一性:ThreadLocal存储的对象与线程一对一绑定,线程之间不受干扰
持久性:只要没有删除,TreadLocal中存储的对象一直存在,线程可以随时访问
3.ThreadLocal使用
a)ThreadLocal
set(Object obj);//将相关对象存入ThreadLocal中
get(); //从ThreadLocal中取出与当前线程相关的对象
remove(); //从ThreadLocal中删除与当前线程相关的对象
b)与线程相关
4.ThreadLocal示例
TestJDBC1.java
package com.chapter7;
import java.util.Random;
/*
* ThreadLacal的使用
*/
public class TestJDBC1 implements Runnable{
//创建线程局部变量personLocal,用来保存Person对象
private final static ThreadLocal personLocal = new ThreadLocal();
public static void main(String[] agrs) {
TestJDBC1 tj = new TestJDBC1();
Thread t1 = new Thread(tj,"a");
Thread t2 = new Thread(tj,"b");
t1.start();
t2.start();
}
public void run(){
//获取当前线程的名字
String currentThreadName = Thread.currentThread().getName();
System.out.println("线程'"+currentThreadName + "'正在运行!");
//产生一个随机数并打印
Random random = new Random();
int age = random.nextInt(100);
System.out.println("线程'" + currentThreadName + "'设置年龄:" + age);
//从ThreadLocal对象中获取一个Person对象,并将随机数年龄插入到对象属性中
Person person = personLocal.get();
//线程首次执行此方法的时候,personLocal.get()肯定为null
if (person == null) {
//创建一个Person对象,并保存到本地线程变量personLocal中
person = new Person();
person.setAge(age);
personLocal.set(person);
}
System.out.println("线程'" + currentThreadName + "'第一次读年龄:" + personLocal.get().getAge());
try {
Thread.sleep(500);
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println("线程'" + currentThreadName + "'第二次读年龄:" + personLocal.get().getAge());
}
}
Person.java
package com.chapter7;
/*
* 测试ThreadLocal
*/
public class Person {
private int age = 0;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
1.银行业务模拟系统需求说明
a)银行业务模拟系统需求
模拟银行日常业务
开户、存款,取款,转账
b)DAO封装
将数据访问代码进行封装
与业务代码实现隔离
重点是DAO实现,模拟业务功能
2.银行业务模拟系统
a)显示层
BankTest.java
b)业务逻辑层
BankBiz.java, BankBizImpl.java
BankAccount.java, BankStatement.java
BankAccountDao.java,BankAccountDaoImpl.java
ConnectionFactory.java, jdbc.properties
c)数据层
MySQL
test数据库
bankaccount表,bankstatement表
d)业务逻辑层
BankBiz.java, BankBizImpl.java
进行各种验证,实现开户,存款,取款,转账功能
BankBiz.java是接口,BankBizImpl.ava实现接口,便于扩展
BankAccount.java, BankStatement.java
实体Bean,封装相关表中的数据,在数据库及业务处理代码之间传递数据(集合)
e)BankAccountDao.java,BankAccountDaoImpl.java
操作bankaccount和bankstatement表中的数据
BankAccountDao.java是接口,BankAccountDaoImpl.java实现接口,便于扩展
f)ConnectionFactory.java, jdbc.properties
ConnectionFactory.java读取配置文件,创建连接池并从连接池获得连接
g)DAO相关代码
BankAccount.java, BankStatement.java
实体Bean,封装相关表中的数据,在数据库及业务处理代码之间传递数据(集合)
BankAccountDao.java,BankAccountDaoImpl.java
操作bankaccount和bankstatement表中的数据
BankAccountDao.java是接口,BankAccountDaoImpl.java实现接口,便于扩展
ConnectionFactory.java, jdbc.properties
ConnectionFactory.java读取配置文件,创建连接池并从连接池获得连接
h)连接池,ThreadLocal,事务…
i)业务完成过程
3.银行业务模拟代码分析
a)转账业务(BankTest.java)
Scanner in = new Scanner(System.in);
print("请输入转出账号:");
long fromaccno = in.nextLong();
print("请输入转入账号:");
long toaccno = in.nextLong();
print("请输入转账金额:");
float balance = in.nextFloat();
BankBizImpl bankBiz = new BankBizImpl();
BankAccountDao dao =
new BankAccountDaoImpl();
bankBiz.setDao(dao);
BankAccount bank = bankBiz.transfer(fromaccno, toaccno, balance);
if(bank!=null){
println("转账成功,账户信息:");
println("账户编号:"+bank.getAccno());
println("账户名称:"+bank.getName());
println(“账户余额:"+bank.getBalance());
}
b)转账业务(BankBizImpl.java)
public BankAccount transfer(long from, long to, float amt) {
BankAccount bankfrom = dao.findAccountByAccno(from);
if(bankfrom==null){
System.out.println(
“转出账户不存在,请重新输入!");
return null;
}
//判断余额是否足够
if(bankfrom.getBalance()
c)转账业务(BankAccountDaoImpl.java)
public BankAccount transfer(BankAccount from, BankAccount to, float amt) {
Connection conn = ConnectionFactory.getConnection();
PreparedStatement pstmt = null;
ResultSet rs = null;
BankAccount bank = null;
try {
conn.setAutoCommit(false);
//源账户减少金额
pstmt = conn.prepareStatement("update bankaccount set balance=balance-? where accno=?");
pstmt.setFloat(1,amt);
pstmt.setLong(2,from.getAccno());
pstmt.executeUpdate();
//目标账户增加金额
pstmt = conn.prepareStatement("update bankaccount set balance=balance+? where accno=?");
pstmt.setFloat(1,amt);
pstmt.setLong(2,to.getAccno());
pstmt.executeUpdate(); /以下代码记录转账
pstmt = conn.prepareStatement("insert into bankstatement(action,txdate,amt,fromaccno,toaccno) values(?,?,?,?,?)");
pstmt.setString(1,"转账");
java.util.Date date = new java.util.Date();
pstmt.setDate(2,new Date(date.getTime()));
pstmt.setFloat(3,amt);
pstmt.setLong(4,from.getAccno());
pstmt.setLong(5,to.getAccno());
pstmt.executeUpdate();
//返回账户信息
pstmt = conn.prepareStatement("select * from bankaccount where accno=?");
pstmt.setLong(1,from.getAccno());
rs = pstmt.executeQuery();
bankaccount = new BankAccount();
rs.next();
bankaccount.setAccno(rs.getLong(1));
bankaccount.setName(rs.getString(2));
bankaccount.setBalance(rs.getFloat(3));
conn.commit();
} catch (SQLException se) {
try {
conn.rollback();
}
catch (SQLException e) {
throw new RuntimeException(e);
}
throw new RuntimeException(se);
} finally {
try {
if(rs!=null){
rs.close();
}
if(pstmt!=null){
pstmt.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
return bankaccount;}
d)转账业务(ConnectionFactory.java)
public class ConnectionFactory {
private static ThreadLocal connThread = new ThreadLocal();
private static Properties pros = System.getProperties();
static {
try {
InputStream is = ConnectionFactory.class.getResourceAsStream("jdbc.properties");
pros.load(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static Connection getConnection() {
Connection con = connThread.get();
if(con == null){
try{
DataSource ds = BasicDataSourceFactory.createDataSource(pros);
con = ds.getConnection();
connThread.set(con);
}catch(SQLException se){
se.printStackTrace();
throw new RuntimeException(se);
} catch (Exception e) {
e.printStackTrace();
}
}
return con;
}
public static void release(){
Connection con = getConnection();
if(con != null){
try{
con.close();
}catch(SQLException se){}
}
connThread.set(null);
}
e)转账业务(jdbc.properties)
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=gbk
username=root
password=root
maxActive=50
maxIdle=20
maxWait=60000
i.数据库产品:MySQL
ii.数据库名称:test
iii.表:bankaccount,bankstatement
f)转账业务完成过程
g)转账业务(运行结果)
开户,存款,取款,列出所有账户信息……
4.DAO总结
a)DAO
实体Bean:将数据库数据封装为对象,在业务逻辑代码、数据访问代码、显示层之间传递
dao:对数据库数据进行添加,修改,删除,查询操作
连接池:提高数据访问效率
b)三层结构
业务逻辑层=业务处理代码+DAO
c)N层结构
显示层--》业务逻辑层--》数据访问层(DAO)--》数据库
d)DAO封装
将数据访问代码封装为一个组件,与业务逻辑代码隔开
使数据访问与业务逻辑分离
应用程序结构清晰,易于维护和扩展
e)实现DAO
JDBC
事务,连接池……
ThreadLocal
三层/N层架构
事务(dao层)--》事务(业务层)