1:什么是数据库的事务?
事务就是DBA(数据库管理员)操作多个sql的时候,可能有一条执行语句可能异常了,其他sql不执行了,就会导致出现紊乱,
将整个sql(多个sql)的执行看成一个"整体",要么同时执行成功,要么同时执行失败!
始终保证的数据的一致性(高并发中,读/写)
2:传统事务特点(重点)ACID
原子性:执行的某业务操作,同时操作多个sql(增删改),要么同时执行成功,要么同时执行失败!
一致性:在实际开发中,多个线程同时去写和读的时候,数据必须一致性
隔离性:事务和事务之间(业务和业务之间)相互独立的, 互不影响!
持续性:就是对增删改这些sql语句,一旦事务提交了,对数据库中表的操作是永久性,即使关机了,数据永久保存!
3:传统事务的隔离级别
读未提交:read uncommited;一个事务读取到另一个没有没有提交的事务(最不安全),出现"脏读" (最严重的问题!)
读已提交:read committed; 有效防止脏读! 会出现另一种问题"不可重复读", 读取到自己本身没有提交的事务的数据前后两次不一致,本身这个事务没有提交,多次读取到的数据必须一致!
可重复读 :mysql的默认隔离级别 (repetable-read) /* 有效防止脏读,不可重复读,可能出现"幻读" -串行话:serializable
4:jdbc的本质是什么?
Jdbc是一个普通的Java类,是数据库厂商提供的驱动jar包,可以实现sun提供一套接口规范!
java.sql.Driver:驱动接口---->驱动jar包--->实现了这个接口
java.sql.Connection:数据库的连接会话--->驱动jar包--->ConnectionImpl实现了这个接口
5:jdbc的7大操作步骤,代码体现
// 7大步骤 后期--->开源框架:就是对原生Jdbc代码的封装+一些配置文件
//1)导入驱动jar包 --mysql-connnecto-java驱动jar包
//2)注册驱动
Class.forName("com.mysql.jdbc.Driver") ;
//3)获取数据库的连接对象
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/库名",
"root",
"123456") ;
//4)准备sql语句:DDL语句或者DML语句
String sql = "insert into employee(name,age,gender,birthday,address) values(xxx,xx,xx,xx,xx,xx)" ;
//5)通过连接对象获取执行对象Statement
Statement stmt = conn.createStatement() ;
//6)执行sql,通用的更新
int count = stme.executeUpdate(sql) ;
//7)释放资源
stmt.close() ;
conn.close() ;
6:jdbc针对DQL语句,遍历结果集
//1)导入驱动jar包 --mysql-connnecto-java驱动jar包
//2)注册驱动
Class.forName("com.mysql.jdbc.Driver") ;
//3)获取数据库的连接对象
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/库名",
"root",
"123456") ;
//4)准备sql语句:DDL语句或者DML语句
String sql = "select 指定的字段列表 from 表名" ;
//5)通过连接对象获取执行对象Statement
Statement stmt = conn.createStatement() ;
//6)执行sql,通用的查询操作
ResultSet rs = stmt.executeQuery(sql) ;
//遍历结果集
while(rs.next()){
//获取数据
//通用的写,列的名称获取/列的索引值获取
XXX 变量= rs.getXXX("字段名称") ;
//自己封装数据...
}
//7)释放资源
stmt.close() ;
conn.close() ;
7:自定义工具类JdbcUtils的步骤
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/库名
user=root
password=123456
class JdbcUtils{
private static String user = null ;
private static String password = null ;
private static String driverClass = null ;
private static String url = null ;
//定义static代码块
static{
//读取配置文件
Properties prop = new Properties() ;
//获取key对应的value,赋值给上面四个成员变量
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties") ;
user = prop.getProperty("user") ;
password = prop.getProperty("password") ;
url = prop.getPrpperty("url") ;
driverClass = prop.getProperty("driverClass") ;
//注册驱动
Class.forName(driverClass) ;
}
private JdbcUtils(){}
public static Connnection getConnection(){
Connection conn = DriverManager.getConnection(url,user,password) ;
return conn ;
}
//释放资源
//带三个参数:ResultSet ,Statment,Connection---针对DQL语句操作
//带两个参数:Satement,Connection--->针对DML语句
}
8:junit单元测试的使用步骤
1)导入junit的核心包: 4.13.1以及依赖包
2)建立测试类---XXXTest
3)定义单元测试方法,在方法上加入@Test
4)方法中要么Assert断言,要么直接测试指定功能(XXXDao--->添加,删除,修改,查询的功能)
9:Statement和PreparedStatement的区别?
1)共同点: 都是可以发送sql到数据库的,都是执行对象,后者继承前者(java.sql.包下的接口)
2)不同点:
2.1)是否会造成sql注入
Statement永远执行的是静态sql语句:语句中存在"硬编码",存在SQL的字符串拼接,就造成sql注入,不安全!
PreparedStatement:永远执行的是参数化的sql语句,全部参数都是"?", 占位符号,有效防止sql的拼接,预防sql注入,提高执行sql的安全性!
2.2)是否会提高sql执行效率
Statement:不会提高sql执行效率, 获取执行对象,然后将sql语句发送数据库(没写一个sql,发一次!),频繁的操作访问数据库
PreparedStatement:大大提高SQL执行效率 参数化sql是在获取PreparedStatement,就已经发送给数据库了,然后在PreparedStatement赋值不同的值;
10:德鲁伊Druid配置文件的参数说明
#这些名称都是DruidDataSoure提供的参数
#连接数据库的驱动类
driverClassName=com.mysql.jdbc.Driver
#连接数据库的url地址:统一资源定位符
url=jdbc:mysql://localhost:3306/myee2302_db_2
#用户名
username=root
#密码
password=123456
#连接池一旦创建,初始化5个连接数量
initialSize=5
#最大连接数量值:默认值8个,自己设定值,和maxIdel:最大空闲数量相等
maxActive=10
#最大等待时间:为毫秒值,一旦连接池中创建连接对象超过了最大连接数量,等待3秒中,如果还连接不上,连接池会产生错误日志,提示"连接超时"
maxWait=3000
11:什么视图 ?
就是一个虚拟表:只是定义视图,表的数据来源于基础表中的(数据库中真实存在表)
作用:保证数据的安全性/简单性(快速查看到真实表的结构,类型....)
12:创建视图
CREATE VIEW <视图名> AS <SELECT语句>
CREATE VIEW view_employee AS
SELECT
id,
NAME,
gender,
age,
salary,
address,
birthday
FROM
employee ;
-- 查看视图的内容
SELECT * FROM view_employee ;
-- 查看视图的结构---查询表的结构语法相同
-- 查询基础表(employee) 它的结构
DESC employee ;
-- 查询指定视图的结构
DESCRIBE view_employee ; -- 简写成功desc 视图名称;
-- 查询当前库中的所有表以及视图的名称
SHOW TABLES ;
-- 查询当前库中的所有表以及视图的名称以及后面的table_type:表类型
SHOW FULL TABLES ;
-- 修改视图的内容
-- ALTER VIEW <视图名> AS <SELECT语句>
ALTER VIEW view_employee
AS
SELECT
id,NAME,salary FROM employee ;
-- 更新视图(视图添加数据/修改数据/删除数据,会直接影响基础表的内容,
-- 一般很少去使用视图去更新基础表的内容)
UPDATE view_employee SET NAME = '姚笛' WHERE id = 2 ;
SELECT * FROM view_employee ;
-- 删除视图:就是drop view 视图名称,多个视图名称;
-- 只是的删除视图的定义,不会影响基础表的任何内容
DROP VIEW view_employee ;
-- 查询employee基础表的内容
SELECT * FROM employee ;
-- 重命名视图跟表的重命名语法一样
-- renname table 视图名 to 新视图名;
CREATE VIEW my_view AS SELECT * FROM employee ;
SELECT * FROM my_view ;
RENAME TABLE my_view TO view_emp;
13:Druid使用步骤
/**
* Druid连接池的使用步骤:
* 1)导包 druid-1.1.10.jar包
* 2)准备好连接池的配置文件
* 3)从连接池获取连接对象
* 提供jar包--->com.alibaba.druid.pool.DruidDataSource--->本质实现了一个接口javax.sql.DataSource
* --->Connection getConnection()
*
*/
public class DruidDemo {
public static void main(String[] args) throws Exception {
//3)创建数据源DruidDataSource对象
//德鲁伊提供的数据源工厂:DruidDataSourceFactory提供静态方法,返回值就是DataSource
//public static DataSource createDataSource(Properties properties)
//创建属性集合列表
Properties prop = new Properties() ;
//读取src下配置文件
InputStream inputStream = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
//将字节输入流加载进来
prop.load(inputStream) ;
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
for(int x = 1 ; x <=11 ; x++){
//System.out.println(dataSource.getConnection());
Connection conn = dataSource.getConnection() ;
if(x==3){
conn.close(); //暂时释放,归还连接池中
}
System.out.println(conn);
}
14:加入连接池自定义工具的步骤
Jdbc方式---加入Druid连接池,----自动的封装配置文件的所有数据
封装一个静态方法--->获取Connection(从连接池获取)
获取DataSource:数据源----> 连接参数(数据库的信息)以及初始化数量,最大激活数量,最大等待时间
释放资源
public class DruidJdbcUtils {
//静态实例--->java.lang.ThreadLocal<T> 模拟线程,每一个用户都有自己的Connection
private static ThreadLocal<Connection> tl = new ThreadLocal<>() ; //里面没有连接对象
//声明一个DataSource接口类型 变量
private static DataSource ds ;
//构造方法私有化
private DruidJdbcUtils(){}
//静态代码块
static{
try {
//1)读取德鲁伊的配置文件,让德鲁伊自己封装配置文件参数
InputStream inputStream = DruidJdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
//创建属性集合列表
Properties prop = new Properties() ;
//加载属性集合列表
prop.load(inputStream) ;
//2)创建DruidDataSource(连接池)
ds = DruidDataSourceFactory.createDataSource(prop) ;
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取DataSource数据源信息 (连接池的所有参数)
public static DataSource getDataSource(){
return ds ;
}
//从数据源(连接池) 获取连接对象
public static Connection getConnection(){
//1)线程本地线程中获取连接对象---ThreadLocal<T>--->T get():从当前线程中获取存储的内容
Connection conn = tl.get() ;
try {
//2)判断
//如果当前conn对象为null,说明当前线程中没有要操作的连接对象
if(conn==null){
//3)从数据源(连接池中)获取Connection
conn = ds.getConnection();
//4)将从数据源中获取到的conn连接对象,绑定当当前线程中
//ThreadLocal<T>--->public void set(T t):绑定
tl.set(conn) ;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return conn ;
}
//释放资源
public static void close(ResultSet rs, PreparedStatement stmt, Connection conn){
if(rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
//从当前线程解绑
tl.remove(); //ThreadLocal<T> :从线程中移出
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//主要针对DDL/DML语句操作释放资源
/* public static void close(Statement stmt,Connection conn){
close(null,stmt,conn);
}*/
public static void close(PreparedStatement stmt,Connection conn){
close(null,stmt,conn);
}
public static void main(String[] args) {
System.out.println(DruidJdbcUtils.getDataSource());
System.out.println(DruidJdbcUtils.getConnection());
}
}
15:连接池的好处
节省资源:当前连接池(DataSource接口)创建之后,就会初始化一些连接对象,节省连接对象的创建;
重复利用:当某个线程持有的连接对象被使用完之后,归还连接池等待下次利用;
提高性能:连接池中:只需要配置好这些连接参数(最基本参数:数据库的相关信息)/连接池中的优化参数,DataSource里的实
现类---DruidDataSource自己封装这里面的所有连接参数;(还可以不断监控连接池中连接数量的变化)
16:使用PreparedStatement完成jdbc操作:DQL语句操作
//导包 (驱动jar包)
//注册驱动
Class.forName("com.mysql.jdbc.Driver") ;
//获取数据库连接对象
Connection conn = DriverManager.getConnecton(
"jdbc:mysql://localhost:3306/库名",
"用户名",
"密码") ;
//sql
String sql = "select * from employee where id = ?" ;
//通过数据库连接对象获取预编译对象,同时发送参数化sql到数据库
PreparedStatement ps = conn.prepareStatement(sql) ;
//对参数进行赋值
ps.setInt(1,id实际值) ;
//通过赋值执行sql语句
Resultset rs = ps.executeQuery() ;
//遍历结果集,封装数据
while(rs.next()){
//获取,封装数据到实体对象中
类名 对象名 = new 类名() ;
对象名.setXXX属性名称(rs.getXXX("column名称")) ;
}
//释放资源
//关闭结果集,关闭预编译对象,关闭连接对象
17:jdbc控制事务
转账业务操作:
同时操作多个账户内容(更新),这些更新语句要么同时执行成功,要么同时执行失败!
public void setAutoCommit(boolean auto) ;参数为true,表示自动提交,如果是false,手动提交
void rollback():事务回滚,撤销之前所有更改,必须释放连接对象,连接对象需要从线程中解绑
void commit():提交事务,将更改数据永久保存,提交完毕,释放连接对象,需要从线程中解绑
18:什么是事务?
针对多个sql或者多张表的sql(增删改),要么同时执行成功,要么同时执行失败,应该将整个业务看成一个整体,一块执行!
事务的特点:原子性,一致性,隔离性,持久性
19:commons-dbutils的使用步骤:
1)导包 commons-dbutils-1.6.jar
2)创建执行器 QueryRunner---> 底层PreparedStatement
public QueryRunner(DataSource ds) 参数就是数据源--->自定义工具获取到了数据源 (自动提交)
public QueryRunner():创建执行器,手动提交
3)准备好sql语句
DML语句---添加/修改/删除
insert into
update
delete from...
QueryRunner提供通用的更新操作:
public int update(Connection conn, String sql, Object... params) throws SQLException :手动提交
public int update(String sql, Object... params):自动提交
DQL语句--- 查询语句
QueryRunner提供的通用查询操作
public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException
第一个参数:查询的sql语句
第二个参数:ResultSetHandler结果集的处理
它的子实现类:BeanHandler---->将查询的某一条记录封装到实体了中(JavaBean:是具体类,属性私有,对外提供setXXX()/getXXX)
public BeanHandler(Class<T> type) ---> 参数针对查询的记录--封装到类名.class中
子实现类:BeanListHandler<T> ---将查询的多条记录封装到List集合中,List集合都是当前类对象
public BeanListHandler(Class<T> type)
子实现类:
ScalarHandler:通过聚合函数(count(列名称),其他max(xx),avg(xxx))查询单行单的列的数据
的结果封装到Object类中
第三个参数:就是赋值的实际参数params,没有参数可以不写
注意事项:
使用commons-dbutils工具库:无论添加/删除/修改/查询数据,
必须保证实体类的属性名称和表的字段名称一一对应,否则数据封装不上去的,永远是null!
如果不对应,可以在(查询语句)--->给这字段给别名(保证别名和实体类的属性名称一致)
实体类的属性名称不要出现大写字母,否则也可能是null值!