一、Web–什么是JDBC?
1.概念
是java程序连接数据的桥梁,通过jdbc驱动java程序可以操作访问数据库软件
2.JDBC的组成
由两种:
1.接口:是由Sun公司定义在JDK中,提供(java.sql包和javax.sql包)给程序员开发使用
2.实现类:由数据库厂商以JAR包的形式商提供
3.JDBC中常用的JAR包
有两种:
1.ojdbc5.jar---jdk5和jdk6的环境中使用
2.ojdbc6.jar---jdk7和jdk8的环境中使用
4.环境的搭建(导入JAR包)
两种方式:
1.普通文本编辑工具:将JAR包所在的路径配置到CLASSPATH环境变量中。例如:CLASSPATH=.;D:\文件目录名\jar包名
2.使用集成开发工具(例如:MyEclipse或者Eclipse):
项目配置JAR包:
第一步:在项目路径下新建一个lib文件夹,将JAR包到文件夹下
第二步:右键选中导入的JAR包,选择build path选项,选择add to build path
项目配置数据库操作窗口:
第一步:选中菜单window-->show view-->others-->在搜索框中搜索db browser并选中
第二步:找到db browser窗口,并右击MyEclipse Derby-->选择new-->在弹出界面中填写name(随意起)、url(数据库地址)、 数据库登录的账号和密码-->点击Add JARs引入jar包的路径-->Save PassWord(保存密码)可选可不选,如果不选,下次要重新输入密码-->最后点击完成
第三步:在项目的src目录下新建一个sql包,里面放入sql文件
二、第一个JDBC程序(六个步骤)
1.注册Driver(加载驱动类)
Class.forName("驱动类的全类名")
eg:Oracle数据库驱动类全类名:oracle.jdbc.OracleDriver
注意:一个JDBC程序中可以注册多个Driver驱动类
2.获取数据库链接
代码:Connection conn = DriverManager.getConnection( 地址,用户名,密码);
注意: 实际负责建立数据库连接的程序是Driver实现类,DriverManager只是一个工具类
3.创建Statement(Sql命令的传送工具)
代码: Statement stm = conn.createStatement();
4.执行sql命令(传送)
三种方法:
1)executeUpdate(sql) : 用来执行insert update delete命令,返回int值(命令影响了几行数据)
2)executeQuery(sql) : 用来执行select命令,返回值为ResultSet(包含了查询结果)
3)execute(sql) : 可以用来执行所有的sql命令,返回boolean值(标志是否有结果集返回)
5.处理结果集
ResultSet接口中提供了next()、getXxx()等方法,处理结果。
注意:一般用于查询数据库中的所有数据(即使用select语句查询)时使用,如果不select语句查询,则一般不处理结果。增删改看情况需不需要处理结果集。
6.释放资源
释放资源事按照生成顺序反向释放。eg:ResultSet引用.close-->Statement引用.close-->Connection引用.close
三、带参sql命令的执行
1.使用Statement执行带参sql
缺点:
1.命令字符串的拼接比较繁琐
2.sql注入
2.使用PreparedStatement执行带参的sql
1.PreparedStatement 是Statement的子接口,可以解决sql注入(字符串拼接)的问题
2.三个步骤:
I:创建PreparedStatement对象( 需要直接指定执行的sql )
代码:PreparedStatement pstm = conn.prepareStatement(sql);
注意:PreparedStatement允许指定 “半成品” 的sql , 允许在sql命令中使用?作为占位符,来代替暂时不方便给定的值
2.PreparedStatement提供了一系列的setXxx()方法为?设置值
eg: PreparedStatement的引用.setInt( ?的下标,?的值 )/setString()/setDouble() /setDate()
3.执行sql通用的两种方法:
PreparedStatement的引用.executeQuery()
PreparedStatement的引用.executeUpdate()
四、编写工具类JdbcUtil
1.基本原则
java代码复用的基本原则:
1.方法封装:
经常反复出现在程序中的一段功能代码(冗余代码),通过方法封装可以提高代码复用性
2.尽量减少“硬编码” :
将可能会发生改变的值直接定义在java程序中(值的改变会导致程序的重新编译)将变化的值定义在“配置文件”
2.配置文件 (properties文件)
1.概念:
用来保存程序运行过程中所需要的一些数据,文件通常用properties/xml结尾
2.properties文件内容格式:
每一行定义一个值,一行由两部分name和value,中间等号或者空格连接
3.集合类Properties :
是Hashtable的子类,主键和值默认都是String类型,处理properties文件的工具,并提供了load( 字节输入流 )函数来读取保存配置文件内容
3.提高工具类的效率
1.将读取文件的代码从函数里移植到静态代码块中 static{ .... }
2.改变流的获取方式:
由
InputStream is = new FileInputStream("bin/jdbc.properties");
变成
InputStream is = 类对象.getResourceAsStream(" 路径从/,/代表src目录 ");
五、O-R mapping映射
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uk89yHDT-1589167148846)(C:\Users\ASUS\AppData\Local\Temp\1557707605524.png)]
1. 实体类作用:
用来封装数据库数据,属性名最好与表中字段名保持一致
2. 函数的返回值:
正常情况必须返回指定类型的值,非正常情况,异常对象可以作为一种返回值形式来表示
六、JDBC的增删改查模板
1.工具类JdbcUtil
public class JdbcUtil {
private static DataSource ds = null;
private static Properties prop = new Properties();
private static final ThreadLocal<Connection> tol = new ThreadLocal<Connection>();
static{
try {
InputStream is = JdbcUtil.class.getResourceAsStream("/cn/Jdbc/Tel_Book/conf/jdbc.properties");
prop.load(is); // 文件所有数据被保存在map里
ds = BasicDataSourceFactory.createDataSource(prop);
Class.forName( prop.getProperty("driverClassName") );
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws Exception{
Connection conn = tol.get();
if( conn== null ){
conn = ds.getConnection();
tol.set(conn);
}
return conn;
}
public static void close(ResultSet rs,Statement stm ){
if(rs!=null) try{rs.close();}catch(Exception e){}
if(stm!=null) try{stm.close();}catch(Exception e){}
}
public static void close( Connection conn){
if(conn!=null) try{conn.close(); tol.remove(); }catch(Exception e){}
}
}
2.增
public void insert(实体类名(Person) 实体类引用(person)){
Connection conn = null;
PreparedStatement pstm = null;
try {
conn = JdbcUtil.getConnection();
String sql = "insert into person values(person_seq.nextval,?,?,?,?,?)";
pstm = conn.prepareStatement(sql);
pstm.setString(1, person.getName());
pstm.setString(2, person.getMobile());
pstm.setString(3, person.getTelphone());
pstm.setString(4, person.getEmail());
pstm.setString(5, person.getCity());
pstm.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("系统忙,请稍后再试");
}finally{
JdbcUtil.close(null, pstm);
}
}
3.删
public void deletePerson(参数为主键(Integer id)) {
Connection conn = null;
PreparedStatement pstm = null;
try{
conn = JdbcUtil.getConnection();
String sql="delete from person where id=?";
pstm = conn.prepareStatement(sql);
pstm.setInt(1, id);
pstm.executeUpdate();
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException("系统忙,请稍后再试");
}finally{
JdbcUtil.close(null, pstm);
}
}
4.改
public void updatePerson(Person person) {
Connection conn = null;
PreparedStatement pstm = null;
try{
conn = JdbcUtil.getConnection();
String sql="update person set name=?,mobile=?,telphone=?,email=?,city=? where id=?";
pstm = conn.prepareStatement(sql);
pstm.setString(1, person.getName());
pstm.setString(2, person.getMobile());
pstm.setString(3, person.getTelphone());
pstm.setString(4, person.getEmail());
pstm.setString(5, person.getCity());
pstm.setInt(6, person.getId());
pstm.executeUpdate();
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException("系统忙,请稍后再试");
}finally{
JdbcUtil.close(null, pstm);
}
}
5.查
查一条数据案列:
public Person QueryPersonById(Integer id) {
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
Person person = null;
try{
conn = JdbcUtil.getConnection();
String sql = "select * from person where id=?";
pstm = conn.prepareStatement(sql);
pstm.setInt(1,id);
rs = pstm.executeQuery();
if(rs.next()){
Integer cardId = rs.getInt("id");
String name = rs.getString("name");
String mobile = rs.getString("mobile");
String telphone = rs.getString("telphone");
String email = rs.getString("email");
String city = rs.getString("city");
person= new Person(cardId, name, mobile, telphone, email, city);
}
return person ;
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException("系统忙请稍后再试");
}finally{
JdbcUtil.close(rs, pstm);
}
}
查所有数据案例:
public List<Person> queryAllPersons() {
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try{
conn = JdbcUtil.getConnection();
String sql = "select * from person";
pstm = conn.prepareStatement(sql);
rs = pstm.executeQuery();
List<Person> list = new ArrayList<Person>();
while(rs.next()){
Integer cardId = rs.getInt("id");
String name = rs.getString("name");
String mobile = rs.getString("mobile");
String telphone = rs.getString("telphone");
String email = rs.getString("email");
String city = rs.getString("city");
Person person= new Person(cardId, name, mobile, telphone, email, city);
list.add(person);
}
return list;
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException("系统忙,请稍后再试");
}finally{
JdbcUtil.close(rs, pstm);
}
}
7、DAO数据访问对象
1.作用
完成对数据库里一张表所有数据访问操作(增删改查)
2.命名规范
1) 为每一张表提供一个与之对应的DAO程序
2) 定义DAO接口,命名时 “表名+DAO"
3)为接口提供实现类,命名时 “接口名+Impl"
3.好处
对调用者屏蔽底层数据库的差异
8、Service( 业务层 )
1.作用
定义方法完成具体的业务需求
2.定义规则
1.每一个业务功能定义一个方法
2.程序的命名规范:
接口:"表明+Service"
实现类:"接口名+Impl"
3.JDBC中的事物控制
1. jdbc中默认的事务提交策略为 “一条命令提交一次” --- 自动提交
2.手动提交 API
I:conn.setAutoCommit( boolean );
true--自动提交 false--手动提交
--- 一经设置,永久生效(在当前conn的生命周期中,一直有效)
II: conn.commit(); conn.rollback();
3.代码结构
try{
conn.setAutoCommit(false);
/*业务代码....*/
conn.commit();
}catch(Exception e){
conn.rollback();
throw new RuntimeException(....);
}
4.给service程序添加事务控制代码
1. 目标:为了事务控制,需要在一个事务内部的不同代码间,使用一个连接对象
2. 解决:使用参数传递的方式解决(将service层的连接对象传给dao层函数)
5.使用ThreadLocal对象解决service层事务控制问题
1.ThreadLocal --- 线程局部变量
一个ThreadLocal对象可以为每一个线程保存一个独占数据
2.使用API
I: 创建对象
ThreadLocal<独占数据的类型> tol = new ThreadLocal<....> ();
II:存数据
tol.set( 数据 );
III:取数据
tol.get() ---> 独占数据
VI:解除与当前线程的绑定
tol.remove()
3.作用
I:wei一个线程锁定一个数据,使得我们在线程的任意代码组成部分里都可以获取到这个数据(一个数据)
II:为不同的线程锁定不同的数据
4.使用ThreadLocal改写JdbcUtil
案例:
private static final ThreadLocal<Connection> tol = new ThreadLocal<>();
public static Connection getConnection() throws Exception {
// 从配置文件中获取values值链接数据库
Connection conn = tol.get();
if (conn == null) {
conn = DriverManager.getConnection(prop.getProperty("url"),
prop.getProperty("username"), prop.getProperty("password"));
tol.set(conn);
}
return conn;
5.理论上,conn应该在线程结束时被关闭,实际开发中,线程结束位置不固定,一般会在事务结束时就关闭连接,关闭同时切记解除conn和当前线程的绑定关系( dao层函数千万不能关闭连接 )
6.业务层开发步骤
I:获取数据库连接,并且控制提交策略为手动提交
II:完成业务功能( 数据校验 , 数据库的访问操作 --- 需要dao的对象 )
III:提交 或者 回滚
VI:释放资源,解绑线程
9、View( 视图层 , 显示逻辑 , 界面)
1.作用
提供一个与用户交互的通道
2.常见代码
1.数据采集
2.调用service层函数完成用户业务需求
3.展示结果数据(正常的结果, 异常对象 )
3.现有程序结构
测试类--视图层--业务层--数据访问层--数据库
4.项目结构
项目包名:
|-- src
|-- com.baizhi.telbook
|-- util包 存放工具类的位置
|-- conf包 存放项目中的配置文件
|-- sql包 存放sql文件(常规sql命令--建表语句)
|-- entity包 存放实体类
|-- dao包 存放与dao相关程序
|-- dao interface
|-- impl包 存放dao接口的实现类
|-- service包 存放service相关程序
|-- service接口
|-- impl包 存放service接口的实现类
|-- view包 存放view程序
|-- test包 存放测试程序
|-- excp包 存放业务异常程序(自定义异常类型)
|-- lib 项目开发过程中需要使用的jar包
10.连接池
1.原理
提前建立好一组数据库连接提供给用户循环使用
2.连接池里的连接与普通连接的区别
1.boolean标志位 : 标志连接池里的连接状态(空闲,繁忙)
2.conn的close方法被改写,不是真正断开连接,而是修改标志位,将连接还给连接池
3.使用dbcp连接池软件
1.入相关jar包(3个)--> lib --> add to build path
commons-collections-3.2.1.jar
commons-dbcp-1.4.jar
commons-pool-1.5.4.jar
2.引入配置文件(dbcp.properties) --> src/conf/.....
driverClassName=oracle.jdbc.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:xe
username=hr
password=hr
initialSize=10
maxActive=50
maxIdle=20
minIdle=5
maxWait=60000
connectionProperties=useUnicode=true;characterEncoding=utf-8
defaultAutoCommit=true
defaultTransactionIsolation=READ_COMMITTED
3.修改JdbcUtil程序 ( 改变连接的获取方式)
public class JdbcUtil {
private static DataSource ds = null;
private static Properties prop = new Properties();
private static final ThreadLocal<Connection> tol = new ThreadLocal<Connection>();
static{
try {
InputStream is = JdbcUtil.class.getResourceAsStream("/cn/Jdbc/Tel_Book/conf/jdbc.properties");
prop.load(is); // 文件所有数据被保存在map里
ds = BasicDataSourceFactory.createDataSource(prop);
Class.forName( prop.getProperty("driverClassName") );
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws Exception{
Connection conn = tol.get();
if( conn== null ){
conn = ds.getConnection();
tol.set(conn);
}
return conn;
}
public static void close(ResultSet rs,Statement stm ){
if(rs!=null) try{rs.close();}catch(Exception e){}
if(stm!=null) try{stm.close();}catch(Exception e){}
}
public static void close( Connection conn){
if(conn!=null) try{conn.close(); tol.remove(); }catch(Exception e){}
}
}
11.jdbc里日期值的处理
1.ava.util.Date(java程序中的日期)转化成java.sql.Date(数据库中的日期)需要借助getTime()方法
案例:
java.util.Date time1 = new java.util.Date();
long time = time1.getTime();
java.sql.Date time2 = new java.sql.Date(time);