什么是JavaWeb ?
约束名称 | 描述 | 关键字 |
---|---|---|
非空约束 | 保证列中所有数据不能有null值 | not null |
唯一约束· | 保证列中所有数据各不相同 | unique |
主键约束 | 主键是一行数据的唯一标识,要求非空且唯一 | primary key |
检查约束 | 保证列中的值满足某一条件 | check |
默认约束 | 保持数据时,未指定值采用默认值 | default |
外键约束 | 外键用来让两个表的数据之间建立链接,保证数据的一致性和完整性 | foreign key |
-- 创建表时添加外键约束
create table 表名(
列名 数据类型,
...
[constraint] [外键名称] foreign key(外键列名) references 主表(主表列名)
);
(2)删除约束
alter table 表名 drop foreign key 外键名称;
一对一:
如:用户和用户信息
一对一关系多用于表拆分,将一个实体中经常使用的字段放一张表,不经常使用的字段放另一张表,用于提升查询性能
分开:
实现方式:在任意一方加入外键,关联另一方主键,并且设置外键为唯一(unique)
例如:
alter table tb_order_goods add constraint fk_order_id foreign key(oreder_id) references tb_order(id);
alter table tb_order_goods add constraint fk_goods_id foreign key(goods_id) references tb_goods(id);
笛卡儿积:取A,B集合所有组合情况
多表查询:从多张表查询数据
语法:
-- 隐式内连接
select 字段列表 from 表1,表2... where 条件
-- 显示内连接
select 字段列表 from 表1 [inner] join 表2 on 条件;
外连接:
语法:
-- 左外连接
select 字段列表 from 表1 乐翻天 [outer] join 表2 on 条件;
-- 右外列表
select 字段列表 from 表1 right [outer] join 表2 on 条件;
子查询概念:
子查询根据查询结果不同,作用不同:
select 字段列表 from 表 where 字段名 = (子查询);
select 字段列表 from 表 where 字段名 in (子查询);
select 字段列表 from (子查询) where 条件;
事务简介:
-- 开启事务
start transaction;
或者 begin;
提交代码
-- 提交事务
commit;
-- 回滚事务
rollback;
事务四大特征:
MySQL事务默认自动提交的
-- 查看事务的默认提交方式
select @@autocommit;
-- 1 自动提交 0 手动提交
-- 修改事务提交方式
set @@autocommit = 0;
JDBC概念:(Java DataBase Connectivity)Java数据库连接
JDBC就是使用Java语音操作关系型数据库的一套API
JDBC好处:
首先创建工程,导入驱动jar包mysql-connector-java-8.0.30.jar(版本不一样)
IDEA将其导入模块库,具体查看步骤
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(url,username,password);
String sql = "update...";
Statement stmt = conn.createStatement();
stmt.executeUpdate(sql);
案例:
public class JDBCDemo {
public static void main(String[] args) throws Exception {
// 1. 注册成功
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接使用自己数据库的用户和密码
String url = "jdbc:mysql://127.0.0.1:3306/itmagua";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
//3.定义sql
String sql = "update student set no =200105 where id = 1;";
//4.执行sql的对象Statement
Statement stmt =conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//返回受影响的行数
//6.处理结果
System.out.println(count);
//7.释放资源
stmt.close();
conn.close();
}
}
DriverManager(驱动管理类)作用:
1. 注册驱动
Class.forName("com.mysql.jdbc.Driver");
提示:
- MySQL5之后的驱动包,可以省略注册驱动的步骤,不写也不会报错
- 自动加载jar包钟
META-INF/services/java.sql.Driver
文件中的驱动类
语法:
jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2...
示例:jdbc:mysql://127.0.0.1:3306/itmagua
细节:
Connection(数据库连接对象)作用:
1. 获取执行SQL对象
Statement createStatement()
PrepatedStatement prepareStatement(sql)
CallableStatement prepareCall(sql)
2. 管理事务
开启事务:
beigin;/start transaction;
提交事务:commit;
回滚事务:rollback;
MySQL默认自动提交事务
开启事务:
setAutoCommit(boolean autoCommit):true
为自动提交事务;false
为手动提交事务,即为开启事务
提交事务:commit;
回滚事务:rollback;
案例:
成功时:
public class JDBCDemo2_DriverManager {
public static void main(String[] args) throws Exception {
// 1. 注册成功
// Class.forName("com.mysql.jdbc.Driver");
//2.获取连接:如果连接的是本机mysql并且端口是默认的3306 可以简化
String url = "jdbc:mysql:///itmagua";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
//3.定义sql
String sql1 = "update student set no =200105 where id = 1;";
String sql2 = "update student set no =200105 where id = 2;";
//4.执行sql的对象Statement
Statement stmt =conn.createStatement();
try {
//开启事务
conn.setAutoCommit(false);
//5.执行sql
int count1 = stmt.executeUpdate(sql1);//返回受影响的行数
int count2 = stmt.executeUpdate(sql2);
//6.处理结果
System.out.println(count1);
System.out.println(count2);
// 提交事务
conn.commit();
} catch (SQLException throwables) {
//回滚事务
conn.rollback();
throwables.printStackTrace();
}
//7.释放资源
stmt.close();
conn.close();
}
}
Statement作用:执行SQL语句
int executeUpdate(sql)
:执行DML、DDL语句
返回值:(1)DML语句影响的行数(2)DDL语句执行喉,执行成功也可能返回0
ResultSet executeQuery(sql)
:执行DQL语句
返回值:ResultSet 结果集对象
为了保证自己写的模块方法没问题,需要对其进行测试
单元测试方法写多少个
一般是一个业务方法对应一个测试方法
测试方法的规范:public void testXxxx(){}
测试方法的方法名:以test开始,假设测试的方法是sum,这个测试方法名:testSum
@Test注释非常重要,被这个注解标注的方法就是一个单元测试方法
单元测试中有两个重要的概念
一个是实际值(被测试的业务方法的真正执行结果)
一个是期望值(执行了这个业务方法之后,你期望的执行结果是多少)
案例:
1、执行DML语句
public class JDBCDemo2_DriverManager {
@Test
public void testDML() throws SQLException {
// 1. 注册成功
// Class.forName("com.mysql.jdbc.Driver");
//2.获取连接使用自己数据库的用户和密码
String url = "jdbc:mysql://127.0.0.1:3306/itmagua";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
//3.定义sql
String sql = "update student set no =200105 where id = 1;";
//4.执行sql的对象Statement
Statement stmt =conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//执行完DML语句,返回受影响的行数
//6.处理结果
// System.out.println(count);
if(count>0){
System.out.println("执行成功");
}else {
System.out.println("执行失败");
}
//7.释放资源
stmt.close();
conn.close();
}
}
public class JDBCDemo2_DriverManager {
@Test
public void testDML() throws SQLException {
// 1. 注册成功
// Class.forName("com.mysql.jdbc.Driver");
//2.获取连接使用自己数据库的用户和密码
String url = "jdbc:mysql://127.0.0.1:3306/itmagua";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
//3.定义sql
String sql = "drop database db2;";
//4.执行sql的对象Statement
Statement stmt =conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//执行完DML语句,返回的可能是删除成功所以为的0
//6.处理结果
// System.out.println(count);
// if(count>0){
// System.out.println("执行成功");
// }else {
// System.out.println("执行失败");
// }
System.out.println(count);
//7.释放资源
stmt.close();
conn.close();
}
}
ResultSet(结果集对象)作用:
ResultSet stmt.executeQuery(sql)
:执行DQL语句
返回值:ResultSet 结果集对象
boolean next()
:(1)将光标从当前位置向前移动一行(2)判断当前行是否为有效行
返回值:
- true:有效行,当前行有数据
- false:无效行,当前行没有数据
xxx getXxx(参数)
:获取数据
xxx:数据类型;如:int getInt(参数);String getString(参数)
参数:
- int:列的编号,从1开始
- String:列的名称
使用步骤:
next()
// 循环判断游标是否是最后一行末尾
while(rs.next()){
//获取数据
rs.getXxx(参数);
}
案例:
public class JDBCDemo2_DriverManager {
@Test
public void testDML() throws SQLException {
// 1. 注册成功
// Class.forName("com.mysql.jdbc.Driver");
//2.获取连接使用自己数据库的用户和密码
String url = "jdbc:mysql:///itmagua?useSSL=false";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
//3.定义sql
String sql = "select * from student";
//4. 获取statement对象
Statement stmt = conn.createStatement();
//5.获取sql
ResultSet rs = stmt.executeQuery(sql);
//6.处理结果,遍历rs中的所有数据
//6.1 光标向下移动一行,并且判断当前是否有数据
while(rs.next()){
//6.2 获取数据 getXxx()
int id = rs.getInt(1);
String name = rs.getString(2);
String no = rs.getString(3);
System.out.println(id);
System.out.println(name);
System.out.println(no);
System.out.println("------------------------");
}
//7.释放资源
rs.close();
stmt.close();
conn.close();
}
}
package com.itmagua.pojo;
public class Account {
private int id;
private String name;
private String no;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", no='" + no + '\'' +
'}';
}
}
实现类:
public class JDBCDemo2_DriverManager {
/*
查询account账户表数据,封装为Account对象中,并且存储到ArrayList集合中
1.定义实体类Account
2. 查询数据,封装到Account对象中
3.将Account对象存入ArrayList集合中
*/
@Test
public void testDML2() throws SQLException {
// 1. 注册成功
// Class.forName("com.mysql.jdbc.Driver");
//2.获取连接使用自己数据库的用户和密码
String url = "jdbc:mysql:///itmagua?useSSL=false";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
//3.定义sql
String sql = "select * from student";
//4. 获取statement对象
Statement stmt = conn.createStatement();
//5.获取sql
ResultSet rs = stmt.executeQuery(sql);
List<Account> list = new ArrayList<>();
//6.处理结果,遍历rs中的所有数据
//6.1 光标向下移动一行,并且判断当前是否有数据
while(rs.next()){
Account account = new Account();
//6.2 获取数据 getXxx()
int id = rs.getInt(1);
String name = rs.getString(2);
String no = rs.getString(3);
account.setId(id);
account.setName(name);
account.setNo(no);
list.add(account);
}
System.out.println(list);
//7.释放资源
rs.close();
stmt.close();
conn.close();
}
}
PreparedStatement作用:
SQL注入:
public class JDBCDemo2_DriverManager {
@Test
public void testLogin() throws SQLException {
// 1. 注册成功
// Class.forName("com.mysql.jdbc.Driver");
//2.获取连接使用自己数据库的用户和密码
String url = "jdbc:mysql:///itmagua?useSSL=false";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
String name = "zhangsan";
String pwd = "123";
//3.定义sql
String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
//4. 获取statement对象
Statement stmt = conn.createStatement();
//5.获取sql
ResultSet rs = stmt.executeQuery(sql);
// 判断登录是否成功
if(rs.next()){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
//7.释放资源
rs.close();
stmt.close();
conn.close();
}
}
// 演示sql注入
@Test
public void testLogin_Inject() throws SQLException {
// 1. 注册成功
// Class.forName("com.mysql.jdbc.Driver");
//2.获取连接使用自己数据库的用户和密码
String url = "jdbc:mysql:///itmagua?useSSL=false";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
String name = "hfkjsfhskj";
String pwd = "' or '1' = '1";
//3.定义sql
String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
System.out.println(sql);
//4. 获取statement对象
Statement stmt = conn.createStatement();
//5.获取sql
ResultSet rs = stmt.executeQuery(sql);
// 判断登录是否成功
if(rs.next()){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
//7.释放资源
rs.close();
stmt.close();
conn.close();
}
密码不一样却登录成功了!
因为:password = 空字符串了 or 1=1恒等式拼接完成之后,由于前面用户名不成立,后面的密码也不成立,故构成了false
or会执行后面为true的条件,所以直接就登录了
这就是SQL注入
PreparedStatement作用:
预编译SQL并执行SQL语句
// SQL语句中的参数值,使用?占位符替代
String sql = "select * from user where username = ? and passsword = ?";
// 通过Connection对象获取,并转入对应的sql语句
PreparedStatement pstmt = conn.prepareStatement(sql);
PreparedStatement对象:setXxx(参数1,参数2):给?赋值
Xxx:数据类型;如setInt(参数1,参数2)
参数:
executeUpdate();/executQuery(); :不需要再传递sql
案例:
1.
public class JDBCDemo2_DriverManager {
@Test
public void testPreparedStatement() throws SQLException {
// 1. 注册成功
// Class.forName("com.mysql.jdbc.Driver");
//2.获取连接使用自己数据库的用户和密码
String url = "jdbc:mysql:///itmagua?useSSL=false";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
String name = "zhangsan";
String pwd = "123";
//3.定义sql
String sql = "select * from tb_user where username = ? and password = ?";
//4. 获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
// 设置?的值
pstmt.setString(1,name);
pstmt.setString(2,pwd);
//5.获取sql
ResultSet rs = pstmt.executeQuery();//不填sql
// 判断登录是否成功
if(rs.next()){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
//7.释放资源
rs.close();
pstmt.close();
conn.close();
}
// 演示sql注入失效
@Test
public void testLogin_Inject() throws SQLException {
// 1. 注册成功
// Class.forName("com.mysql.jdbc.Driver");
//2.获取连接使用自己数据库的用户和密码
String url = "jdbc:mysql:///itmagua?useSSL=false";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url,username,password);
String name = "hfkjsfhskj";
String pwd = "' or '1' = '1";
//3.定义sql
String sql = "select * from tb_user where username = ? and password = ?";
//4. 获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
// 设置?的值
pstmt.setString(1,name);
pstmt.setString(2,pwd);
//5.获取sql
ResultSet rs = pstmt.executeQuery();
// 判断登录是否成功
if(rs.next()){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
//7.释放资源
rs.close();
pstmt.close();
conn.close();
}
}
原理
PrepareStatmenet好处:
① PreparedStatment预编译功能开启:useServePrepStmts=true
② 配置MySQL执行日志(重启MySQL服务后生效)
log-output=FILE
general-log=1
general_log_file="D:\mysql.log"
slow-query-log=1
slow_query_log_file="D:\mysql_slow.log"
long_query_time=2
PrepareStatment原理:
数据库连接池是个容器,负责分配、管理数据库连接(Connection);
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;
释放空闲时间最大空闲时间的数据库连接来避免因为没有释放数据库连接遗漏;
好处:
标准接口:DataSource
Connection getConnection()
常见的数据库连接池:
Druid(德鲁伊):
public class DruidDemo {
public static void main(String[] args) throws Exception {
//1.导入jar包
//2.定义配置文件
//3.加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("/jdbc-demo/src/druid.properties"));
//4.获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//5.获取数据库连接Connection
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
}
public class Brand {
// 主键
private int id;
// 品牌
private String brandName;
// 企业
private String companyName;
// 排序字段
private int ordered;
// 描述信息
private String description;
// 状态:0:禁用 1:启用
private Integer status ;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public int getOrdered() {
return ordered;
}
public void setOrdered(int ordered) {
this.ordered = ordered;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "Brand{" +
"id=" + id +
", brandName='" + brandName + '\'' +
", companyName='" + companyName + '\'' +
", ordered=" + ordered +
", description='" + description + '\'' +
", status=" + status +
'}';
}
}
Connection
select * from tb_brand;
List
public class BrandTest {
@Test
public void testSelectAll() throws Exception {
//1.获取connection
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("/jdbc-demo/src/druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据库连接Connection
Connection conn = dataSource.getConnection();
//2.定义sql
String sql = "select * from tb_brand;";
//3.获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//4.设置参数
//5.执行sql
ResultSet rs = pstmt.executeQuery();
//6.处理结果list封装Brand对象,转载list集合
Brand brand = null;
List<Brand> brands = new ArrayList<>();
while(rs.next()){
//获取数据
int id = rs.getInt("id");
String brandName = rs.getString("brand_name");
String companyName = rs.getString("company_name");
int ordered = rs.getInt("ordered");
String description = rs.getString("description");
int status = rs.getInt("status");
//获取Brand对象
brand = new Brand();
brand.setId(id);
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setOrdered(ordered);
brand.setDescription(description);
brand.setStatus(status);
//转载集合
brands.add(brand);
}
System.out.println(brands);
//7.释放资源
rs.close();
pstmt.close();
conn.close();
}
}
insert into tb_brand(brand_name,company_name,ordered,description,status)values(?,?,?,?,?);
public class BrandTest {
@Test
public void testAdd() throws Exception {
//模拟接收页面提交的参数
String brandName = "捞的一";
String companyName = "愣头青";
int ordered = 1;
String description = "皮的很不谈";
int status = 1;
//1.获取connection
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("/jdbc-demo/src/druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据库连接Connection
Connection conn = dataSource.getConnection();
//2.定义sql
String sql = "insert into tb_brand(brand_name,company_name,ordered,description,status)values(?,?,?,?,?);";
//3.获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//4.设置参数
pstmt.setString(1,brandName);
pstmt.setString(2,companyName);
pstmt.setInt(3,ordered);
pstmt.setString(4,description);
pstmt.setInt(5,status);
//5.执行sql
int count = pstmt.executeUpdate();
//6.处理结果
System.out.println(count>0);
//7.释放资源
pstmt.close();
conn.close();
}
}
update tb_brand
set brand_name = ?,
company_name= ?,
ordered = ?,
description = ?,
status = ?
where id = ?
public class BrandTest {
@Test
public void testUpdat() throws Exception {
//模拟接收页面提交的参数
String brandName = "捞的一";
String companyName = "愣头青";
int ordered = 1000;
String description = "皮的很谈";
int status = 1;
int id = 4;
//1.获取connection
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("/jdbc-demo/src/druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据库连接Connection
Connection conn = dataSource.getConnection();
//2.定义sql
String sql = "update tb_brand\n" +
"set brand_name = ?,\n" +
"\tcompany_name= ?,\n" +
"\tordered = ?,\n" +
"\tdescription = ?,\n" +
"\tstatus = ?\n" +
"where id = ?";
//3.获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//4.设置参数
pstmt.setString(1,brandName);
pstmt.setString(2,companyName);
pstmt.setInt(3,ordered);
pstmt.setString(4,description);
pstmt.setInt(5,status);
pstmt.setInt(6,id);
//5.执行sql
int count = pstmt.executeUpdate();
//6.处理结果
System.out.println(count>0);
//7.释放资源
pstmt.close();
conn.close();
}
}
delete from tb_brand where id = ?
public class BrandTest {
@Test
public void testDeleteById() throws Exception {
//模拟接收页面提交的参数
int id = 4;
//1.获取connection
//加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream("/jdbc-demo/src/druid.properties"));
//获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//获取数据库连接Connection
Connection conn = dataSource.getConnection();
//2.定义sql
String sql = "delete from tb_brand where id = ?";
//3.获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
//4.设置参数
pstmt.setInt(1,id);
//5.执行sql
int count = pstmt.executeUpdate();
//6.处理结果
System.out.println(count>0);
//7.释放资源
pstmt.close();
conn.close();
}
}