脑子太笨,必须得记录下来一些文字,方便回来查询。

这是我的第二次学习JDBC的笔记,看的是传智播客——李勇老师的JDBC系列,已看到第23集。

分析在实际项目中该如何应用JDBC

一个简单用户相关的数据访问层

  1. J2EE三层架构简介:表示层 、业务逻辑层、数据访问层,三层之间用接口隔离。
  2. 定义domain对象User,定义存取用户的接口。

  3. 用JDBC实现接口。

  4. 用配置文件(properties)和反射实现与具体类的耦合。

用图来表示:

在真实的项目开发中,我们能不能返回ResultSet对象呢? 如下例代码:

static ResultSet read() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
//2.建立连接
conn = JdbcUtils.getConnection();
//3.创建语句
st = conn.createStatement();
//4.执行语句
rs = st.executeQuery("select id,name,birthday,money from user");
//5.处理结果
while(rs.next()) {
System.out.println(rs.getObject("id")+"\t"+rs.getObject("name")+
"\t"+rs.getObject("birthday")+"\t"+rs.getObject("money"));
}
return rs;//连接关闭,Statement、ResultSet都失效了。
} finally {
JdbcUtils.free(rs, st, conn);
}
}

在main()方法中调用:

ResultSet rs = read();

这个其实是不可以的,当Connection关闭之后,ResultSet中的数据你就拿不到了(Statement、ResultSet都失效了)。如果我们要进行传值需要定义个domain对象。

我们重点关注数据访问层的代码如何书写

1、定义domain对象User以及存取用户的接口:

import cn.itcast.jdbc.domain.User;

public interface UserDao {
public void addUser(User user); public User getUser(int userId); public User findUser(String loginName, String password); public void update(User user); public void delete(User user);
}
import java.util.Date;

public class User {
private int id;
private String name;
private Date birthday;
private float 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 Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public float getMoney() {
return money;
}
public void setMoney(float money) {
this.money = money;
} }

2、用JDBC实现接口。在实现的过程中,准确一点说会出现SQLException。关于这个异常的处理,很多工作2年的程序员都不知道怎么样处理,所以对于此异常,定当重视,通常我们结合Service层讲解DAO层的异常处理的方式。

就拿addUser(user)方法来说,中间是有可能出现SQLException的,在处理异常的时候,不能catch住异常之后什么都不做,最起码要打印一下堆栈,最好的方式是将这个异常转化为RuntimeException抛出。做法如下:

建立一个DaoException继承RuntimeException,如下:

public class DaoException extends RuntimeException {

    /**
*
*/
private static final long serialVersionUID = 1L; public DaoException() {
// TODO Auto-generated constructor stub
} public DaoException(String message) {
super(message);
// TODO Auto-generated constructor stub
} public DaoException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
} public DaoException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
} public DaoException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
} }

之后JDBC实现接口的过程中,就抛出DaoException异常,如下(代码太多,折叠之):

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; import cn.itcast.jdbc.JdbcUtils;
import cn.itcast.jdbc.dao.DaoException;
import cn.itcast.jdbc.dao.UserDao;
import cn.itcast.jdbc.domain.User; public class UserDaoJdbcImpl implements UserDao { @Override
public void addUser(User user) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//2.建立连接
conn = JdbcUtils.getConnection();
//3.创建语句
String sql = "insert into user (name,birthday,money) values (?,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1, user.getName());
ps.setDate(2, new java.sql.Date(user.getBirthday().getTime()));
ps.setFloat(3, user.getMoney());
//4.执行语句
ps.executeUpdate();
} catch(SQLException e) {
throw new DaoException(e.getMessage(), e);
} finally {
JdbcUtils.free(rs, ps, conn);
}
} @Override
public User getUser(int userId) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
User user = null;
try {
//2.建立连接
conn = JdbcUtils.getConnection();
//3.创建语句
String sql = "select id,name,birthday,money from user where id = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, userId);
//4.执行语句
rs = ps.executeQuery();
//5.处理结果
while(rs.next()) {
/*
* 优化①处
*/
user = mappingUser(rs);
}
} catch(SQLException e) {
throw new DaoException(e.getMessage(), e);
} finally {
JdbcUtils.free(rs, ps, conn);
}
return user;
} @Override
public User findUser(String loginName, String password) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
User user = null;
try {
//2.建立连接
conn = JdbcUtils.getConnection();
//3.创建语句
String sql = "select id,name,birthday,money from user where name = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, loginName);
//4.执行语句
rs = ps.executeQuery();
//5.处理结果
while(rs.next()) {
/*
* 优化①处
*/
user = mappingUser(rs);
}
} catch(SQLException e) {
throw new DaoException(e.getMessage(), e);
} finally {
JdbcUtils.free(rs, ps, conn);
}
return user;
} private User mappingUser(ResultSet rs) throws SQLException {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setMoney(rs.getFloat("money"));
user.setBirthday(rs.getDate("birthday"));
return user;
} @Override
public void update(User user) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//2.建立连接
conn = JdbcUtils.getConnection();
//3.创建语句
String sql = "update user set name = ?,birthday = ?,money = ? where id = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, user.getName());
ps.setDate(2, new java.sql.Date(user.getBirthday().getTime()));
ps.setFloat(3, user.getMoney());
ps.setInt(4, user.getId());
//4.执行语句
ps.executeUpdate();
} catch(SQLException e) {
throw new DaoException(e.getMessage(), e);
} finally {
JdbcUtils.free(rs, ps, conn);
}
} @Override
public void delete(User user) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
//2.建立连接
conn = JdbcUtils.getConnection();
//3.创建语句
st = conn.createStatement();
//4.执行语句
String sql = "delete from user where id = "+user.getId();
st.executeUpdate(sql);
} catch(SQLException e) {
throw new DaoException(e.getMessage(), e);
} finally {
JdbcUtils.free(rs, st, conn);
}
} }

用配置文件(properties)和反射实现与具体类的耦合(?),此时就要用到工厂模式了。

DaoFactory类如下(视频说代码很经典,谁知道呢?):

import java.io.InputStream;
import java.util.Properties; public class DaoFactory {
/*
* 注意两个static属性之间的顺序
* 如果搞反,那么属性userDao始终为空!
*/
private static UserDao userDao = null;
private static DaoFactory instance = new DaoFactory(); private DaoFactory() {
try {
Properties prop = new Properties(); /*
* 方式一
* 缺点:路径是写死的,如果我们的配置文件改变了地方,就找不到文件了 。
*/
//FileInputStream fis = new FileInputStream("src/daoconfig.properties"); /*
* 方式二
* 优点:用类加载器(马丹,涉及到反射技术,又是一个要补的地方)的方法
* 来得到一个文件的输入流,只要这个文件在classpath路径下(其实编译的xxx.class文件和配置文件
* 就在根目录下bin目录中,而次bin目录被自动加载到classpath变量值中(别问我why?我也不知道))就能找到。
*/
InputStream fis = DaoFactory.class.getClassLoader()//类加载器(???)
.getResourceAsStream("daoconfig.properties");//daoconfig.properties只要在classpath路径下,就可以加载进来,更加灵活
prop.load(fis);
String userDaoClass = prop.getProperty("userDaoClass");
/*
* 涉及到反射技术
*/
Class clazz = Class.forName(userDaoClass);//将类加载到JVM
userDao = (UserDao)clazz.newInstance();//实例化一个对象
//System.out.println(userDao);
} catch (Throwable e) {
throw new ExceptionInInitializerError(e);
} }
public static DaoFactory getInstance() {
return instance;
} public UserDao getUserDao() {
//System.out.println(userDao);
return userDao;
}
}

整体的框架图应该如这幅模样:

JDBC事务处理

关于事务,我已经在《浅谈事务》一文中详细记录过,在此不赘述了。我们只关注JDBC是如何处理事务的。

示例1(用代码来体现):

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; public class TxIsolateTest {
public static void main(String[] args) throws SQLException {
test();
} static void test() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
/*
* 设置事务为手动提交,一说也叫打开事务。
*/
conn.setAutoCommit(false);
/*
* 设置事务的隔离级别,这是一个超麻烦的问题,李勇老师也是敷衍过去!
*/
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
String sql = "update user set money = money - 10 where id = 1";
st = conn.createStatement();
st.executeUpdate(sql); sql = "select money from user where id = 2";
rs = st.executeQuery(sql);
float money = 0.0f;
if(rs.next()) {
money = rs.getFloat("money");
}
if(money > 400)
throw new RuntimeException("已经超过最大值!");
sql = "update user set money = money + 10 where id = 2";
st.executeUpdate(sql);
/*
* 提交事务
*/
conn.commit();
} catch (SQLException e) {
if(conn != null)
/*
* 回滚事务,rollback()中不加任何参数,即为回滚所有操作
*/
conn.rollback();
throw e;
} finally {
JdbcUtils.free(rs, st, conn);
}
}
}

示例2:

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement; public class SavePointTest {
public static void main(String[] args) throws SQLException {
test();
} static void test() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
Savepoint sp = null;
try {
conn = JdbcUtils.getConnection();
conn.setAutoCommit(false);
st = conn.createStatement();
String sql = "update user set money = money - 10 where id = 1";
st.executeUpdate(sql);
/*
* 设置保存点
*/
sp =
conn.setSavepoint(); sql = "update user set money = money - 10 where id = 3";
st.executeUpdate(sql); sql = "select money from user where id = 2";
rs = st.executeQuery(sql);
float money = 0.0f;
if(rs.next()) {
money = rs.getFloat("money");
}
if(money > 300)
throw new RuntimeException("已经超过最大值!");
sql = "update user set money = money + 10 where id = 2";
st.executeUpdate(sql);
conn.commit();
} catch (RuntimeException e) {
if(conn != null && sp != null) {
conn.rollback(sp);//回滚到保存点上去,再提交,这样保证到保存点之前那些操作都是有效的(只回滚一部分操作)
conn.commit();
}
throw e;
} catch (SQLException e) {
if(conn != null)
conn.rollback();
throw e;
} finally {
JdbcUtils.free(rs, st, conn);
}
}
}

JTA分布式事务的简要介绍(李勇老师也是敷衍过去了)

跨越多个数据源的事务,使用JTA容器(是啥,不知道?)实现事务。

分成两阶段提交。

代码格式总是如此:

javax.transaction.UserTransaction tx = (UserTransaction)ctx.lookup(“jndi(?)Name");
tx.begin();
//connection1 connection2 (可能来自不同的数据库)…
tx.commit();//tx.rollback();

JDBC第二次学习的更多相关文章

  1. 20145213《Java程序设计》第二周学习总结

    20145213<Java程序设计>第二周学习总结 教材学习内容总结 本周娄老师给的任务是学习教材的第三章--基础语法.其实我觉得还蛮轻松的,因为在翻开厚重的书本,一股熟悉的气息扑面而来, ...

  2. 20145330孙文馨 《Java程序设计》第二周学习总结

    20145330孙文馨第二周学习总结 第二周相比于第一周对java语言有了深一点的了解,也意识到多敲代码才是学习计算机语言的最好方法. 教材内容总结 类型.变量与运算符 *基本类型 整数(short. ...

  3. 20145337 《Java程序设计》第二周学习总结

    20145337 <Java程序设计>第二周学习总结 教材学习内容总结 Java可分基本类型与类类型: 基本类型分整数(short.int.long).字节(byte).浮点数(float ...

  4. 20135328信息安全系统设计基础第二周学习总结(vim、gcc、gdb)

    第三周学习笔记 学习计时:共8小时 读书:1 代码:5 作业:1 博客:7 一.学习目标 熟悉Linux系统下的开发环境 熟悉vi的基本操作 熟悉gcc编译器的基本原理 熟练使用gcc编译器的常用选项 ...

  5. 《Java程序设计》第二周学习总结

    20145224陈颢文<Java程序设计>第二周学习总结 教材学习内容总结 一.类型.变量与运算符 1.类型 整数: 可细分为为short整数(占2字节),int整数(占4字节),long ...

  6. 20155304田宜楠 2006-2007-2 《Java程序设计》第二周学习总结

    20155304田宜楠 2006-2007-2 <Java程序设计>第二周学习总结 教材学习内容总结 一.类型与变量 1.类型 整数: 可细分为为short整数(占2字节),int整数(占 ...

  7. 2017面向对象程序设计(Java)第二周学习总结

    2017面向对象程序设计(Java)第二周学习总结 直系学妹学弟们好!额...不要问我为什么把学妹放前面,我也不知道!我只是你们和蔼可亲的学长一枚而已.也不要问为什么是第二周学习总结而不是第一周,因为 ...

  8. 201521123038 《Java程序设计》 第二周学习总结

    201521123038 <Java程序设计> 第二周学习总结 1.本章学习总结 学会在Java程序中使用函数,使程序层次更清晰 使用StringBuilder编写代码,减少内存空间的占用 ...

  9. 201521123093 java 第二周学习总结

    201521123093 <java程序设计> 第二周学习总结 一.第二周学习总结 答:(1)关于进一步使用码云管理代码,本周才真正学会了如何将Eclipse里的代码上传到码云中,并且能够 ...

随机推荐

  1. windows phone版的一个儿教app

    昨天下午看见一个园友写的一篇关于儿教的api,看了也就两三个接口,所以数据处理应该不会太复杂,主要是界面的效果,要求可能比较高.于是我就重新自己写了一个app,实现很简单,花的时间比较多的地方应该是在 ...

  2. 010--VS2013 C++ 平面地图贴图

    先准备好地图的小图片: //全局变量HDC mdc;HBITMAP fullmap;const int rows = 8, cols = 8; //-------------------------- ...

  3. VS2013中如何更改主题颜色(深色)和恢复默认的窗口布局

    1.通常情况下,我们会根据个人爱好更改VS2013的主题颜色,一开始我喜欢白色,后来我偏爱深色. 依次选择:工具->选项->常规->主题->深色->确定,ok 2.我们在 ...

  4. MSSQL Transaction[事务] and Procedure[存储过程]

    --事务分三种 --1.显示事务 --我们手动begin transaction ...... commit transaction/rollback transaction --上面这种写法叫做“显 ...

  5. Netsharp快速入门(之4) 基础档案(之C 实体建模 计量单位、商品、往来单位)

    作者:秋时 杨昶   时间:2014-02-15  转载须说明出处 3.3.2   基础档案建模 1.在基础档案项目,右击,选择新建包, 2.录入包的名称,录入名称.完成后点确定 3.3.2.1 计量 ...

  6. SQLServer BCP 命令的使用

    现在有一个包含数据的文件,每个字段用“|”分隔,现在要把这些数据导入到数据库的表中. 数据文件如下: R001|20150710 可以使用如下命令: bcp testDB.dbo.testTable ...

  7. HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...

  8. Poj2420 A Star not a Tree? 模拟退火算法

    题目链接:http://poj.org/problem?id=2420 题目大意:每组数据中给n个点(n<=100),求平面中一个点使得这个点到n个点的距离之和最小. 分析:一开始看到这个题想必 ...

  9. 【BZOJ】【3261】最大异或和

    可持久化Trie 嗯……同样搞个前缀异或和,然后将x与sum异或一下,就是在[l-1,r-1]中找x^sum的最大异或值了.同样可持久化Trie搞搞即可(模板还是没背全啊……sad /******** ...

  10. ffmpeg iOS 编译

    编译模拟器版本1 到https://github.com/yuvi/gas-preprocessor下载gas-preprocessor.p并拷贝到/usr/sbin目录中2 下载ffmpeg源码.h ...