JDBC
sum公司, 为了简化和统一Java语言对于数据库的操作, 与各大数据库厂商协同制订了一系列的 接口 , �由各大数据库厂商对这套接口进行实现.
jar文件:
一般使用Jar文件 , 使用在两个操作:
-
把写好的代码, 封装为jar应用程序, 可以双击使用 , 例如QQ等等桌面应用程序
-
封装一系列的class , 在编写代码时, 可以将这个jar文件引入到新的项目中 , 用来引用这一系列的类 !
引入jar文件的方式 *****
- 在项目中 右键新建文件夹 , 命名为lib (右击项目根目录, 点击new–>folder)
- 将要引入的jar文件粘贴到文件夹中
- 右击文件夹中的jar文件
选择: build-path --> add to build path
使用jdbc 操作数据库的前提
确保windows中的oracleXETNSListener服务是开启的
如果服务关闭, 且无法启动:
原因:
- 防火墙未关闭
- 杀毒软件未卸载 , (会报毒 / 优化开启启动项)
- 更改过计算机名称
- 自己手动关闭
终极解决方案:
先尝试重装数据库, 然后做系统!
数据库连接地址 *****
本机地址:
- 127.0.0.1
- localhost
数据库默认侦听端口号: 1521
数据库连接的完整的地址:
格式:
主协议:子协议//主机地址:端口号/数据库名称
例如:
- oracle数据库的连接地址:
jdbc:oracle:thin:@127.0.0.1:1521/xe
- mysql数据库的连接地址:
jdbc:mysql://127.0.0.1:3306/数据库名称
JDBC连接步骤 *****
-
加载数据库驱动
驱动地址: oracle.jdbc.OracleDriver
oracle.jdbc.driver.OracleDriverClass.forName(“oracle.jdbc.driver.OracleDriver”);
-
通过驱动管理器(DriverManager类) 获取连接数据库的连接对象(getConnection())
Connection conn = DriverManager.getConnection(“jdbc:oracle:thin:@localhost:1521/xe”,“system”,“123456”);
-
通过连接对象 , 获取SQL的执行环境(Statement)
Statement state = conn.createStatement(); -
通过执行环境 执行SQL语句
state.execute(“insert into dongfei values(dongfei_id_seq.nextval,‘董飞加长版’,88)”); -
释放资源, 关闭连接(需要释放资源的有两个,1执行环境 2连接对象)
state.close();
conn.close();
DriverManager类
1.获取数据库连接
static Connection getConnection(url,username,password);
- 参数1. 数据库的连接地址
- 参数2. 数据库的帐号
- 参数3. 数据库的密码
Connection类
创建一个SQL执行环境:
Statement createStatement()
Statement类
-
boolean execute(String sql):
用来执行一条SQL语句
返回值为boolean类型, 返回true表示是查询语句 -
int executeUpdate(String sql):
用来执行DML语句 (update|insert|delete)
返回值为int类型, 表示当前执行的SQL语句 , 对数据库表格的影响行数! -
ResultSet executeQuery(sql):
用来执行SELECT语句 ,返回的是ResultSet类型的数据, 也就是结果集
使用executeUpdate操作数据库
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521/xe","system","123456");
Statement state = conn.createStatement();
int count = state.executeUpdate("delete from dongfei");
System.out.println("共删除了:\t"+count+"\t条数据");
state.close();
conn.close();
DriverManager类
1.获取数据库连接
static Connection getConnection(url,username,password);
- 参数1. 数据库的连接地址
- 参数2. 数据库的帐号
- 参数3. 数据库的密码
Connection类
创建一个SQL执行环境:
Statement createStatement()
Statement类
-
boolean execute(String sql):
用来执行一条SQL语句
返回值为boolean类型, 返回true表示是查询语句 -
int executeUpdate(String sql):
用来执行DML语句 (update|insert|delete)
返回值为int类型, 表示当前执行的SQL语句 , 对数据库表格的影响行数! -
ResultSet executeQuery(sql):
用来执行SELECT语句 ,返回的是ResultSet类型的数据, 也就是结果集
ResultSet
结果集 !
常用方法:
游标滚动的方法:
1. next(): 将游标下移, 移动成功返回true , 移动失败返回false , 下一行不存在会导致游标移动失败
2. privious(): 将游标上移, 移动成功返回true , 移动失败返回false , 上一行不存在会导致游标移动失败
3. absolute(int rownum) 移动到指定行
4. beforeFirst(): 移动到第一行
5. afterLast(): 移动到最后一行
因为next方法, 当下一行移动失败, 数据不存在时, 会返回false , 那么我们可以使用它循环遍历结果集:
while(resultSet.next()){
resultSet.getXXX
...
}
获取当前游标所在行数据的方法:
getXXX方法:
需要获取某一列的数据时, 使用getXXX方法 , 传入列名即可!
int value = resultSet.getInt(列名);
int value = resultSet.getInt(int 列的索引);
String value = resultSet.getString(列名);
String value = resultSet.getString(列的索引);
Object value = resultSet.getObject(列名);
Object value = resultSet.getObject(列的索引);
SQL注入
用户输入的内容, 在SQL语句拼接过程中, 完成了一条逻辑发生变化的新的SQL语句 !
例如:
原SQL语句拼接为:
String sql = "select id from user15 where username='"+user.getUserName()+"' and password='"+user.getPassWord()+"'";
用户输入的帐号密码分别为:
请输入您的帐号:
suibian
请输入您的密码:
suibian’ or ‘1’='1
组成的SQL语句:
select id from user15 where username=‘suibian’ and password=‘suibian’ or ‘1’=‘1’
解决SQL注入问题
使用预编译SQL语句 进行参数的传递
更改执行环境 Statement
使用新的环境: PreparedStatement
在通过连接对象 获取一个预编译的SQL环境(PreparedStatement)时, 需要传递 一个SQL语句 !
在这个语句中 可以出现? , ? 表示准备填充的参数值!
使用步骤:
1. 通过连接对象, 获得一个预编译的SQL执行环境
PreparedStatement state conn.prepareStatement(sql);
例如:
String sql = "select id from user15 where username=? and password=?";
PreparedStatement state = conn.prepareStatement(sql);
2.向预编译参数列表中 传递值:
预编译的SQL语句中可以包含0-n个问号, 每一个问号表示一个需要传递的值
我们通过PreparedStatement它的setXXX方法,来完成参数的传递
在传递参数时, 需要指定问号的索引, 问号的索引从1开始
例如:
state.setString(1,user.getUserName());
state.setString(2,user.getPassWord());
3. 执行语句:
ResultSet result = state.executeQuery();
PreparedStatement
常用方法:
填充预编译的参数:
- setXXX(问号索引,值)
向预编译的SQL的?中传递值
参数1. 问号的索引 ,从1开始
参数2. 填充到? 中的值
- execute()
- executeUpdate();
- executeQuery();
上面的三个方法 与 Statement中方法的含义一致, 只不过不存在参数!
Properties类与Properties文件
Properties是Java中的一个类, 是Map集合的子类, 可以存储和获取键值对!
在Java中它也对应一种文件格式,(xxx.properties)
可以很快速的将一个合理的properties文件 转换为内存中的对象
这个类 常用的地方:
1. 应用程序的配置文件
2. 程序国际化中
如何编写properties文件
在src目录下, 创建一个文件, 命名为xxx.properties
在文件中编写键值对:
一行表示一个键值对 , 键与值之间使用等号连接
例如:
username=xxxxx
password=xxxxx
如何将一个properties文件转换为properties对象
-
获取一个指向properties文件的输入流
如果文件存储在src的根目录, 可以通过如下方式快速获取:
InputStream is = class.getClassLoader().getResourceAsStream(“xxx.properties”); -
创建一个Properties对象, 并调用load方法,传入流, 进行数据的读取
Properties ppt = new Properties();
ppt.load(is); -
从对象中取出键值对
String value = ppt.getProperty(key)
事务
在SQL> dml操作, 需要结束事务!
JDBC中 , 事务是自动提交的, 每一条dml语句的执行, 会立即提交事务!
但是我们在一些逻辑中, 也存在需求, 需要自己手动控制事务!
JDBC中事务操作的三个方法:
通过连接对象(Connection对象)操作这个三个方法:
- setAutoCommit(boolean flag)
设置事务的提交方式是否为自动. 默认为true 表示自动提交, false表示手动提交
当设置false以后, 在jdbc中每一条的DML语句 不会再自动提交事务!
- commit(): 提交事务
- rollback(): 回滚事务!
银行转账的案例
董飞买高帆的肉, 付款的场景
create table test15_x(id number,name varchar2(30),rmb number);
未加入事务时, 错误的案例
Connection conn = DBUtil2.getConnection();
Statement state = conn.createStatement();
System.out.println("董飞高高兴兴的去买肉~ ");
System.out.println("董飞 共消费:大腰子3个 , 慈母手中线5个");
state.executeUpdate("update test15_x set rmb=250000 where id=1");
if(1==1) {
throw new RuntimeException("停电了, 哈哈哈哈哈哈");
}
state.executeUpdate("update test15_x set rmb=750050 where id=2");
System.out.println("执行完毕");
事务手动提交 修复逻辑BUG
Connection conn = DBUtil2.getConnection();
//设置了事务的手动提交
conn.setAutoCommit(false);
Statement state = conn.createStatement();
System.out.println("董飞高高兴兴的去买肉~ ");
System.out.println("董飞 共消费:大腰子3个 , 慈母手中线5个");
state.executeUpdate("update test15_x set rmb=250000 where id=1");
if(2==1) {
throw new RuntimeException("停电了, 哈哈哈哈哈哈");
}
state.executeUpdate("update test15_x set rmb=750050 where id=2");
conn.commit();
System.out.println("执行完毕");
批处理
把多条SQL语句 放到一组 一起执行!
对于多条的SQL语句, 采用批处理, 对于数据库的更改是一次!
通过Statement进行操作
addBatch(sql); 将SQL语句加入批处理
executeBatch():执行一批SQL语句!
批处理是不存在返回值 !
批处理与事务的区别:
批处理: 只是将多条SQL语句 放到一起一次执行, 多条SQL语句之间不存在任何的关系, 一个SQL语句发生错误, 不会影响其他的SQL语句的操作!
事务: 将多条SQL语句看作一个整体, 要么一起成功,要么一起失败 !
连接池
实现连接池
使用两个Jar文件来实现:
文件是apache提供的 : dbcp.jar(连接池) pool.jar(连接池实现的依赖库)
-
这个线程池会预读本地文件 , 进行数据库的连接配置:
需要在src根目录, 创建一个properties文件:
#驱动地址 driverClassName=oracle.jdbc.OracleDriver #连接地址 url=jdbc:oracle:thin:@localhost:1521 #帐号 username=system #密码 password=123456 #初始化的连接数量 initialSize=10 #最大的连接数量 maxActive=200 #最大空闲连接数量 maxIdle=10 #最小的空闲连接诶数量 minIdle=1 #超时时间(毫秒) maxWait=15000
-
在Java代码中, 将上面的配置文件, 变为Properties对象
InputStream is = DBCPUtil.class.getClassLoader().getResourceAsStream(“dbcp.properties”);
Properties ppt = new Properties();
//加载一个流指向的文件
ppt.load(is); -
通过连接池工厂对象 获取一个连接池
DataSource ds = BasicDataSourceFactory.createDataSource(ppt); -
获取连接对象
Connection conn = ds.getConnection();
-
使用完毕连接 , 正常关闭连接即可, 连接池会自动回收!
礼拜天复习:
- 网络编程+多线程 (TCP+多线程实现)
- 集合HashMap
- jdbc
<<学员考试管理系统>>