首先你要有一个Java项目,然后依赖了mysql驱动,过程略,这里介绍一下jdbc的基本使用,实际开发是用不到的,都是Spring结合Mybatis或者Hibernate。
基本使用
public void f2() throws Exception{
//注册驱动
//Class.forName("com.mysql.jdbc.Driver"); // 除了Driver是jdbc的类,其余都是Java的类
DriverManager.registerDriver(new Driver());
//获取连接 ctrl+o 整理包
Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/day07", "root", "1234"); // 高版本的有一个警告,用SSL:jdbc:mysql://localhost:3306/test?useSSL=true
//编写sql
String sql="select * from category";
//创建语句执行者
PreparedStatement st=conn.prepareStatement(sql);
//设置参数
//执行sql
ResultSet rs=st.executeQuery();
//处理结果
while(rs.next()){
System.out.println(rs.getString("cid")+"::"+rs.getString("cname"));
}
//释放资源.
rs.close();
st.close();
conn.close();
}
//插入一条数据 注:JdbcUtils是自己封装的类
public void f3(){
Connection conn=null;
ResultSet rs=null;
PreparedStatement st=null;
try {
//获取连接
conn=JdbcUtils.getConnection();
//编写sql
String sql="insert into category values(?,?)";
//获取语句执行者
st=conn.prepareStatement(sql);
//设置参数
st.setString(1, "c006");
st.setString(2, "户外");
//执行sql
int i=st.executeUpdate();
//处理结果
if(i==1){
System.out.println("success");
}else{
System.out.println("fail");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
JdbcUtils.closeResource(conn, st, rs);
}
}
public class JdbcUtils {
// 获取连接
public static Connection getConnection() throws ClassNotFoundException, SQLException {
// 注册驱动 ctrl+shift+f格式化代码
Class.forName("com.mysql.jdbc.Driver");
// 获取连接 ctrl+o 整理包
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day07", "root", "1234");
return conn;
}
/**
* 释放资源
* @param conn 连接
* @param st 语句执行者
* @param rs 结果集
*/
public static void closeResource(Connection conn, Statement st, ResultSet rs) {
closeResultSet(rs);
closeStatement(st);
closeConn(conn);
}
/**
* 释放连接
* @param conn 连接
*/
public static void closeConn(Connection conn){
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn=null;
}
}
/**
* 释放语句执行者
* @param st 语句执行者
*/
public static void closeStatement(Statement st){
if(st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
st=null;
}
}
/**
* 释放结果集
* @param rs 结果集
*/
public static void closeResultSet(ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs=null;
}
}
}
jdbc-api详解
所有的包 都是 java.sql 或者 javax.sql
DriverManager:管理了一组jdbc的操作 类
常用方法:
了解:注册驱动
static void registerDriver(Driver driver) :
通过查看 com.mysql.jdbc.Driver的源码 有如下代码
static {
try {
java.sql.DriverManager.registerDriver(new Driver());//这段代码我们已经写过
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
驱动注册了两次.我们只需要将静态代码块执行一次,类被加载到内存中会执行静态代码块,并且只执行一次.
现在只需要将类加载到内存中即可:
方式1:
★Class.forName("全限定名");//包名+类名 com.mysql.jdbc.Driver
方式2:
类名.class;
方式3:
对象.getClass();
掌握:获取连接
static Connection getConnection(String url, String user, String password)
参数1:告诉我们连接什么类型的数据库及连接那个数据库
协议:数据库类型:子协议 参数
mysql: jdbc:mysql://localhost:3306/数据库名称
oracle: jdbc:oracle:thin@localhost:1521@实例
参数2:账户名 root
参数3:密码
Connection:连接 接口
常用方法:
获取语句执行者:
(了解)Statement createStatement() :获取普通的语句执行者 会出现sql注入问题
★PreparedStatement prepareStatement(String sql) :获取预编译语句执行者
(了解)CallableStatement prepareCall(String sql):获取调用存储过程的语句执行者
了解:
setAutoCommit(false) :手动开启事务
commit():提交事务
rollback():事务回滚
Statement:语句执行者 接口
PreparedStatement:预编译语句执行者 接口
常用方法:
设置参数:
setXxx(int 第几个问号,Object 实际参数);
常见的方法:
setInt
setString
setObject
执行sql:
ResultSet executeQuery() :执行 r 语句 返回值:结果集
int executeUpdate() :执行cud 语句 返回值:影响的行数
ResultSet:结果集 接口
执行查询语句之后返回的结果
常用方法:
boolean next():判断是否有下一条记录,若有返回true且将光标移到下一行,若没有呢则返回false
光标一开始处于第一条记录的上面
获取具体内容
getXxx(int|string)
若参数为int :第几列
若参数为string:列名(字段名)
例如:
获取cname的内容可以通过
getString(2)
getString("cname")
常用方法:
getInt
getString 也可以获取int值
getObject 可以获取任意
事务
事务总结:
事务的特性:★★★
ACID
原子性:事务里面的操作单元不可切割,要么全部成功,要么全部失败
一致性:事务执行前后,业务状态和其他业务状态保持一致.
隔离性:一个事务执行的时候最好不要受到其他事务的影响
持久性:一旦事务提交或者回滚.这个状态都要持久化到数据库中
不考虑隔离性会出现的读问题(都是对于两个事务来说的)★★
脏读:在一个事务中读取到另一个事务没有提交的数据
不可重复读:在一个事务中,两次查询的结果不一致(针对的update操作)
虚读(幻读):在一个事务中,两次查询的结果不一致(针对的insert操作)
通过设置数据库的隔离级别来避免上面的问题(理解)
read uncommitted 读未提交 上面的三个问题都会出现
read committed 读已提交 可以避免脏读的发生
repeatable read 可重复读 可以避免脏读和不可重复读的发生
serializable 串行化 可以避免所有的问题
了解
演示脏读的发生:
将数据库的隔离级别设置成 读未提交
set session transaction isolation level read uncommitted;
查看数据库的隔离级别
select @@tx_isolation;
避免脏读的发生,将隔离级别设置成 读已提交
set session transaction isolation level read committed;
不可避免不可重复读的发生.
避免不可重复读的发生 经隔离级别设置成 可重复读
set session transaction isolation level repeatable read;
演示串行化 可以避免所有的问题
set session transaction isolation level serializable;
锁表的操作.
四种隔离级别的效率
read uncommitted>read committed>repeatable read>serializable
四种隔离级别的安全性
read uncommitted<read committed<repeatable read<serializable
开发中绝对不允许脏读发生.
mysql中默认级别:repeatable read
oracle中默认级别:read committed
java中控制隔离级别:(了解)
Connection的api
void setTransactionIsolation(int level)
level是常量
package com.itheima.utils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
// 数据库工具另一种封装,使用了第三方连接池
public class DataSourceUtils {
private static ComboPooledDataSource ds=new ComboPooledDataSource();
private static ThreadLocal<Connection> tl=new ThreadLocal<>();
/**
* 获取数据源
* @return 连接池
*/
public static DataSource getDataSource(){
return ds;
}
/**
* 从当前线程上获取连接
* @return 连接
* @throws SQLException
*/
public static Connection getConnection() throws SQLException{
Connection conn = tl.get();
if(conn==null){
//第一次获取 创建一个连接 和当前的线程绑定
conn=ds.getConnection();
//绑定
tl.set(conn);
}
return conn;
}
/**
* 释放资源
*
* @param conn
* 连接
* @param st
* 语句执行者
* @param rs
* 结果集
*/
public static void closeResource(Connection conn, Statement st, ResultSet rs) {
closeResource(st, rs);
closeConn(conn);
}
public static void closeResource(Statement st, ResultSet rs) {
closeResultSet(rs);
closeStatement(st);
}
/**
* 释放连接
*
* @param conn
* 连接
*/
public static void closeConn(Connection conn) {
if (conn != null) {
try {
conn.close();
//和当前的线程解绑
tl.remove();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
/**
* 释放语句执行者
*
* @param st
* 语句执行者
*/
public static void closeStatement(Statement st) {
if (st != null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
st = null;
}
}
/**
* 释放结果集
*
* @param rs
* 结果集
*/
public static void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
}
/**
* 开启事务
* @throws SQLException
*/
public static void startTransaction() throws SQLException{
//获取连接//开启事务
getConnection().setAutoCommit(false);;
}
/**
* 事务提交
*/
public static void commitAndClose(){
try {
//获取连接
Connection conn = getConnection();
//提交事务
conn.commit();
//释放资源
conn.close();
//解除绑定
tl.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 事务回滚
*/
public static void rollbackAndClose(){
try {
//获取连接
Connection conn = getConnection();
//事务回滚
conn.rollback();
//释放资源
conn.close();
//解除绑定
tl.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public class AccountDao4DB {
public void accountOut(String fromUser, String money) throws SQLException {
//创建queryrunner
QueryRunner qr = new QueryRunner();
//编写sql
String sql="update account set money =money - ? where name =?";
//执行sql
qr.update(DataSourceUtils.getConnection(), sql, money,fromUser);
}
public void accountIn(String toUser, String money) throws SQLException {
// TODO Auto-generated method stub
QueryRunner qr=new QueryRunner();
String sql="update account set money =money + ? where name =?";
qr.update(DataSourceUtils.getConnection(), sql, money,toUser);
}
}
public class AccountService4DB {
/**
* 转账
* @param fromUser 转出方
* @param toUser 转入方
* @param money 金额
* @throws Exception
*/
public void account(String fromUser, String toUser, String money) throws Exception {
AccountDao4DB dao = new AccountDao4DB();
try {
//0.开启事务
DataSourceUtils.startTransaction();
//1.转出
dao.accountOut(fromUser,money);
int i=1/0;
//2.转入
dao.accountIn(toUser,money);
//3.事务提交
DataSourceUtils.commitAndClose();
} catch (Exception e) {
e.printStackTrace();
DataSourceUtils.rollbackAndClose();
throw e;
}
}
}