文章目录
1. 数据库的事务
什么是事务
在实际业务操作过程中,可能同时需要执行多张表的sql语句或者一张表的多个sql(update,delete,insert into)使用事务将多个sql语句进行管理,如果整个sql执行没问题,提交事务(表示整个完成);如果有问题,回滚事务(撤销这个sql语句的所有操作,回滚到原来起始点,操作sql之前的操作)
1.1 事务特点 ACID
- 原子性(Atomicity) : 操作多个sql,要么同时执行成功或者要么同时执行失败
- 一致性(Consistency) : 频繁进行写入操作时,保证数据内容一致(针对具体的业务操作)
- 隔离性(Isolation) : 事务和事务之间是独立的,互不影响的
- 持久性(Durability) : 事务在提交commit之后, 对数据的添加,修改,删除是永久性的
1.2 数据库的隔离级别
read uncommitted 读未提交,会造成"脏读"
read committed 读已提交,能有效防止"脏读",但会出现"不可重复读"
repeatable read 可重复读,mysql默认级别,有效防止"脏读"和"不可重复读",但是可能会出现"幻读"的问题
serializable 串行化
-- 三个指令 :
start transaction -- 开启事务 , 如果没有开启事务,针对sql语句都是默认提交
执行sql语句
-- 如果没有问题
commit -- 提交事务
-- 如果有问题
rollback -- 回滚事务
-- mysql5.7查询事务的隔离级别的指令
SELECT @@tx_isolation ;
-- 修改隔离级别
set global transaction isolation level 级别的名称;
-- mysql8.0以上查询事务的隔离级别指令
select tranaction_isolation
2. JDBC
Java Database Connectivity : Java数据库连接
使用Java语言编写的应用程序直接操作数据库,对数据库表进行添加,删除,修改,查询
sun提供的接口, 数据库厂商提供数据库驱动jar包(sun提供的接口的实现类)
2.1 JDBC原生操作
/**
* jdbc原生操作步骤:
* 1)导入MySQL的驱动jar包
* 2)注册驱动
* 3)创建数据库的连接对象Connection
* 4)通过连接对象来获取执行对象Statement
* 5)准备好sql语句
* 6)执行sql语句
* 7)释放资源
*/
public class JDBCDemo {
@SuppressWarnings("all")
public static void main(String[] args) throws Exception {
//1)导入驱动MySQL的jar包
//2)注册驱动
Class.forName("com.mysql.jdbc.Driver");
//3)创建数据库的连接对象
Connection root = DriverManager.getConnection("jdbc:mysql://localhost:3306/库名", "用户名", "密码");
//4)通过连接对象获取执行对象
Statement statement = root.createStatement();
//5)准备好sql语句
String sql = "insert into student (name, gender) values('张三','男')";
//6)执行sql语句
int count = statement.executeUpdate(sql);
System.out.println("共影响了" + count + "行");
//7)释放资源
statement.close();
root.close();
}
}
2.2 自定义工具类
public class JDBCUtils {
//private static String driverClass = null;
private static String url = null;
private static String user = null;
private static String password = null;
//构造方法私有化
private JDBCUtils() {
}
static {
try {
//读取src下的jdbc.properties配置文件
InputStream resourceAsStream = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
//创建属性集合列表
Properties prop = new Properties();
prop.load(resourceAsStream);
//获取value,并给成员变量赋值
//driverClass = prop.getProperty("driverClass");
url = prop.getProperty("url");
user = prop.getProperty("user");
password = prop.getProperty("password");
//注册驱动
//Class.forName(driverClass);
Class.forName(prop.getProperty("driverClass"));
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
//对外提供静态方法,获取连接对象
public static Connection getConnection() {
try {
//获取连接对象并返回
return DriverManager.getConnection(url, user, password);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
//释放资源
public static void close(ResultSet resultSet, Statement statement, Connection connection){
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static void close(Statement statement, Connection connection) {
close(null, statement, connection);
}
}
/*
jdbc.properties
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/库名
user=用户名
password=密码
*/
2.3 Statement来模拟用户登录操作,有什么弊端
Statement 本身执行的静态sql语句—>存在SQL拼接,造成sql注入!
当前表中只有两位用户
使用statement来模拟用户登录,sql语句中存在拼接,输入错误的用户名及密码,依然显示登录成功,所以使用statement来执行sql语句,是不安全的
2.4 PrepareStatement
以后不会用Statement,以后都是PreparedStatement预编译对象
/**
* 根据id值查询员工,将员工数据封装在员工类中
*/
@Override
public Employee selectEmpById(int id) throws SQLException {
//声明Employee对象
Employee employee = null;
//注册驱动,获取数据库连接对象
Connection connection = JDBCUtils.getConnection();
//sql语句
String sql = "select * from employee where id = ? ;" ;
//通过连接对象获取执行对象Statement
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,id);
//执行sql语句
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
employee = new Employee();
employee.setId(resultSet.getInt("id"));
employee.setName(resultSet.getString("name"));
employee.setAge(resultSet.getInt("age"));
employee.setGender(resultSet.getString("gender"));
employee.setAddress(resultSet.getString("address"));
employee.setBirthday(resultSet.getDate("birthday"));
}
//释放资源
JDBCUtils.close(resultSet, preparedStatement, connection);
return employee;
}
2.5 Statement 和PreparedStatement的区别
共同点:
能够将sql语句发送给数据库进行操作,都称为执行对象
后者继承前者
不同点:
1)是否能够造成SQL注入
Statement操作的是静态sql语句,存在sql语句的字符串拼接,会存在安全漏洞,造成SQL注入
PreparedStatement预编译对象,发送的sql数据,是一种参数化sql,不存在sql拼接,相对于Statement更安全,不会造成SQL注入
2)执行sql语句效率的区别
Statement执行sql语句的效率比较低
PreparedStatement执行sql语句的效率相对来说比较高
Statement是执行静态sql语句,存在sql语句拼接,容易出现sql注入的问题
PreparedStatement可以对sql语句进行预编译,我们只需要填入相关参数,
有效防止了sql注入的问题
2.6 JDBC控制事务
/*
*void setAutoCommit(boolean autoCommit) throws SQLException
* 是否开启手动提交,参数true,就是自动提交,false,禁用自动提交,手动提交----->相当于mysql的指令 start transaction;
*void rollback() throws SQLException撤销在当前事务中所做的所有更改----->事务回滚方法---->相当于msyql指令 rollback;
* void commit()throws SQLException使上次提交/回滚之后所做的所有更改都将永久性 (提交事务)---->mysql的指令 commit;
*
* Jdbc控制事务:当某个业务执行过程中需要同时指定多个sql(添加/删除/修改)需要将这个多个sql看成一个整体,他们要么
* 同时执行成功,要么同时执行失败!
*
* 需求:
* account表:针对多个账户更新操作,"转账的操作"
*/
public class JdbcDemo {
public static void main(String[] args) {
//现在使用JDBC控制事务
Connection conn = null ;
PreparedStatement ps = null ;
PreparedStatement ps2 = null ;
try {
//获取数据库连接对象
conn = JdbcUtils.getConnection();
//开启事务
//void setAutoCommit(boolean autoCommit) throws SQLException
conn.setAutoCommit(false) ;//禁用自动提交
//sql语句
String sql1 = "update account set balance = balance -? where id= ? " ;
String sql2 = "update account set balance = balance +? where id = ?" ;
//获取预编译对象
ps = conn.prepareStatement(sql1);
//赋值
ps.setInt(1,500);
ps.setInt(2,3);
//将sql2进行发送数据库,获取预编译对象
ps2 = conn.prepareStatement(sql2);
//赋值
ps2.setInt(1,500) ;
ps2.setInt(2,4);
//通过预编译对象执行sql
int count = ps.executeUpdate();
//操作过程中,给一段代码(有问题的代码)
//int i = 10 /0 ;//除数不能0 try中的某行代码一出问题,就执行catch语句,处理异常
int count2 = ps2.executeUpdate();
System.out.println(count+"---"+count2);
//更新完上面的所有操作,正常提交数据
conn.commit();
System.out.println("转账成功");
} catch (ArithmeticException throwables) {
try {
//回滚事务
//void rollback() throws SQLException撤销在当前事务中所做的所有更改---
conn.rollback();
//回滚完之后,手动提交
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace(); //交个jvm处理 将异常信息打印控制台
//System.out.println("出问题了...除数为0");
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
//释放资源
JdbcUtils.close(ps,conn);
JdbcUtils.close(ps2,conn);
}
}
}
2.7 数据库连接池概念以及使用步骤
跟线程池一样,都属于"池化技术"
早期的dbcp
c3p0
现在使用阿里提供的连接池 Druid 德鲁伊(为监控而生)
提供连接池的jar包 druid.jar
后期使用sun提供的接口---java.sql.DataSource(数据源接口) 代替DriverManager
public Connection getConnection() ; 连接池的jar包来实现接口
连接池的好处
会创建一个固定的可重复用的连接对象,当某个线程使用完毕这个连接对象,
将连接对象归还连接池中!
使用步骤
1)导入druid的jar包
2)准备好连接池的配置文件
配置好数据库的连接信息以及一些连接参数(最大连接数量, 超时时间, 空闲数量)
3)创建连接池对象--->数据源DataSource接口不能实例化,
com.alibaba.druid.pool.DruidDataSource它具体类,可以创建
4)DruidDataSourceFactory 连接池数据源工厂类
加入Druid的好处
1)资源重用; 针对连接池提供的参数----初始化连接数量,最大激活数量,最大等待时间
等等, 就是"共享资源"----->"资源池"
2)连接对象被释,将连接对象归还给连接池,大大提高系统性能!(防止资源浪费)
3)防止连接对象被泄露掉,强制将使用完的连接对象必须归还给连接池!
4)Druid连接池 为监控而生(一直在监听资源池中的连接数量)
2.8 加入连接池后对JDBCUtils的优化
public class JdbcUtilsWithDruid {
//成员变量
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>(); //类一加载,就创建线程
private static DataSource dataSource; //数据源
//无参构造方法私有化
private JdbcUtilsWithDruid() {
}
//静态代码块
static {
try {
//创建新的属性集合列表
Properties properties = new Properties();
//读取druid.properties
InputStream resourceAsStream = JdbcUtilsWithDruid.class.getClassLoader().
getResourceAsStream("druid.properties");
//将资源文件输入流中的内容加载到属性集合列表properties中
properties.load(resourceAsStream);
//将配置文件进行加载,DruidDataSource自动封装
//通过DruidDataSourceFactory创建数据源
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//定义方法,获取数据源对象
public static DataSource getDataSource() {
return dataSource;
}
//定义方法,创建连接对象
public static Connection getConnection() {
//从当前线程获取连接对象
Connection conn = threadLocal.get();
try {
//判断当前线程中的连接对象是否为null
if (conn == null) {
//如果为null,则从连接池中获取连接对象
Connection connection = dataSource.getConnection();
//将连接池中获取的连接对象绑定在当前线程中
threadLocal.set(connection);
return connection;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return conn;
}
//释放资源
public static void close(ResultSet rs, Statement 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();
//从当前线程中解绑
threadLocal.remove();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//复用上面的close,第一个参数为null
public static void close(Statement stmt,Connection conn){
close(null,stmt,conn);
}
public static void main(String[] args) {
DataSource dataSource = JdbcUtilsWithDruid.getDataSource();
System.out.println(dataSource);
Connection connection = JdbcUtilsWithDruid.getConnection();
System.out.println(connection);
}
}
2.9 DButils
common-Dbutils的使用步骤
1)导入dbutils.jar包
2)创建执行对象
public QueryRunner(DataSource ds)----->自动提交方式 (前期都用这个)
public QueryRunner() ----->空参构造---手动提交(牵扯事务的使用)
3)准备sql语句 update/delete/insert /select...
4)执行
QueryRunner针对update/delete/insert----通用方法
int update(String sql,Object[]...params):参数1:sql语句 参数2:就是可变参数,给占位符赋值 (属于自动提交更新)
int update(Connection conn,String sql,Object[]...params) 更新方法
//通用的查询方法
public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params)
//参数1:sql语句
//参数2:结果集的处理---接口--->需要子实现类
BeanListHandler<T> :将数据库查询的多条记录--->封装List<T>集合中
BeanHandler<T>:将数据库中查询的某条记录---->封装某个实体类中
ScalarHandler<T>:将数据库查询的记录--->封装Object类中---返回的数据单行单列的数据(聚合函数)---->查询总记录数
//参数3:可变参数,在select语句如果有条件查询,传入条件值;如果没有参数,不需要传!
引入DButils后的JDBCUtils
public class JdbcUtilsByDruid {
//模拟线程
private static ThreadLocal<Connection> threadLocal = new ThreadLocal();
private static DataSource dataSource;
private JdbcUtilsByDruid() {
}
static {
try {
//读取配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src/druid.properties"));
//通过DruidDataSourceFactory获取数据源(连接池)
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取数据源
public static DataSource getDataSource() {
return dataSource;
}
//获取连接对象
public static Connection getConnection() {
try {
//从当前线程中获取连接对象
Connection connection = threadLocal.get();
//判断从线程中获取的对象是否为null
if (connection == null) {
//如果为null,则从连接池中获取
connection = dataSource.getConnection();
//将从连接池中获取的对象绑定到当前线程
threadLocal.set(connection);
}
return connection;
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
//不需要关闭资源,CommonDbutils.jar包中的QueryRunner执行对象会自动关闭
}
/*
druid.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/库名
username=用户名
password=密码
//初始化数量
initialSize=5
//最大连接数据
maxActive=10
//最大等待时长
maxWait=3000
*/
3. HTML
Hypert Text Markup Language:超文本记语言
网页标签
常见的文本标签
1)标题标签h1-h6 :从大到小的标题
2)段落标签 p
3)滚动标签marquee
属性:
behivour:滚动的方式
slide:默认从右滚到左边结束
alternate:默认从右滚动到左边然后来回滚动
默认值 scroll:穿梭滚动
srollamount:滚动速度,正数值 值越大,速度越快
direction:滚动方向,默认left,从右到左
rigth从左到右
bgcolor:背景颜色
4) div标签和span标签
div:占一行空间
span:行内标签---在一行上,不会换行
div----层级布局去使用 div+Css-----完成页面布局
5)引用标签:blockquote ----
针对某个段落的文字进行解释说明,自带段落缩进的效果
6)原样输出 pre标签,按照文本的原先格式---原封不动的展示!
7)上下标标签 sup和sub
上标 sup使用居多----结合html转义字符
版权所有 © ----©
注册商品 ®
8)无序列表 ul li
ul
type属性 列表项前的标记 默认值 disc(实心原点)
circle:空心原点
square:正方形
9)有序列表
ol li
ol里面 type属性的默认值从1开始
10)超链接标签 a标签
属性:href:连接到本地地址或者服务器地址(url地址:同意资源定位符)
协议://域名/地址
协议
http协议--https--联网
thunder://迅雷协议
file://本地文件协议
后面用的服务器 tomcat --window系统本地部署
linux系统---远程部署
http://localhost:8080/findproduct
127.0.0.1
域名 -- 绑定 -- ip地址
target属性:
打开新页面地址的方式
默认值:_self 当前页面直接打开
_blank:新建一个窗口打开
11)超链接
<a ></a>
属性:
href: 连接到本地地址或者服务器地址(url地址:统一资源定位符)
协议://域名/地址
http://
thunder://迅雷协议
file://本地文件协议
target: 打开新页面地址的方式
默认值: _self 当前页面直接打开
_blank 新建窗口打开
超链接应用
<a href="跳转url地址" target="打开方式">文本内容</a>
锚链接的使用
同一个页面使用
a)创建一个锚点 (创建一个标记)
<a name="锚点名称"></a>
b)创建跳转连接
<a href="#锚点名称">跳转</a>
在不同页面上使用
a)在另一个页面某个位置创建一个锚点 (创建一个标记)
<a name="锚点名称"></a>
b)在当前页面中,进行跳转链接
<a href="另一个页面地址#锚点名称">跳转</a>
12)表格标签 table
<table></table>
html语言中只有行的概念 tr, 没有列的概念 td : 理解为列
tr 一行中有多少个td
属性:
要表格边框线 border 边框线 单位px
表格对齐方式 align left right center
bgcolor 背景色
width和height 宽度和高度
cellspacing 设置单元格和边框线的距离
子标签
tr : 行
td : 是一个普通单元格
th : 是一个特殊单元格(表格的表头 自动居中,加粗)
caption : 表格的标题标签
普通单元格合并
colspan : 合并列,当前单元格占的格子数
rowspan : 合并行,当前单元格占的格子数
13)表单标签 form
<form></form>
表单场景 : 注册或者登录
注册--将用户的信息提交后端服务器上,校验用户信息是否存在,如果存在,不能注册;
登录---将用户信息提狡服务器上,查看是否有这个用户,有才能的登录;
表单提交的时候,里面所有的表单项标签必须有一个name属性
---后端服务器才能知道用户的输入内容
属性:
action : url地址 将表单中的表单项的数据提交到后台服务器地址上
method : 表单的提交工具
get/post
常见表单标签的表单项
跟input 标签相关的表单项
input type = "text" 文本输入框
input type = "password" 密码输入框
input type = "radio" 单选按钮-
input type = "checkbox" 复选框
input type = "date" 日期组件
input type = "file" 文件上传组件
普通按钮
input type = "button" 必须和value="属性值"
特殊按钮
input type = "submit" 表单提交按钮
input type = "reset" 重置按钮, 清空表单项
select : 下拉菜单
option : 下拉选项
14)框架标签 frame
整个结构是2个或者2个以上的html组成,不能使用frame(只能包含一个html页面)
需要使用 frameset框架集,不能body共存,要么在加载在他前面,或者删除body
15)图像标签 img
scr属性 : 连接到图片地址(可以是本地图片或者网络图片)
width: 图片宽度 指定像素px或者百分比(占整个宽度分辨率的百分之几)
heigh: 图片高度 指定像素px或者百分比(占整个宽度分辨率的百分之几)
title : 当鼠标悬浮在图片上的时候,有提示信息
alt : 替代文本 当这个图片失效(地址找不到),他会给一个信息描述