导语
本系列的导语与java复习系列相同
1.JDBC
1.1 JDBC概述
全称:( Java DataBase Connectivity ) 即Java 数据库连接
定义:是使用Java语言操作关系型数据库的一套API
功能:java代码通过jdbc这个接口与不同的数据库进行连接,数据库驱动即为jdbc这个接口的实现类,因此JDBC中定义了所有操作关系型数据库的规则
本质:是接口【sun公司定义的一套操作所有关系型数据库的规则】
不同数据库厂商实现接口,提供了jar包
故:使用JDBC 让驱动jar包执行操作
优点:
- 使用jdbc可以用相同的java语言操作不同数据库
- 替换数据库不影响java代码
在具体使用时,操作哪个关系型数据库就需要导入该数据库的驱动包即可
1.2 JDBC原理
想使用java操作数据库,基本的思路是:
第一步:编写Java代码
第二步:Java代码将SQL发送到MySQL服务端
第三步:MySQL服务端接收到SQL语句并执行该SQL语句
第四步:将SQL语句执行的结果返回给Java代码
1.2.1 基本JDBC代码
实现jdbc的流程是:
1.创建工程,导入驱动jar包
2.编写代码
public static void main(String[] args) throws Exception {
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接
String username = "root";
String password = "123456";
String url = "jdbc:mysql://127.0.0.1:3306/test";
Connection conn = DriverManager.getConnection(url, username, password);
// 3.定义sql
String sql = "UPDATE yuangong SET id = 123";
// 4.获取执行sql的对象
Statement statement = conn.createStatement();
// 5,执行sql
int count = statement.executeUpdate(sql);//受影响的行数
// 6.处理结果
System.out.println(count);
// 7.释放资源
statement.close();//后执行的先关闭
conn.close();
}
记忆:
最基本的JDBC编写共有七步
1.注册驱动 |
确定用那个数据库 |
2.获取连接 | 连接数据库 |
3.定义SQL语句 | 执行什么操作 |
4.获取执行SQL对象 | 让获取到的连接来找人干活(执行sql) |
5.执行SQL | 让找来的人执行sql |
6.处理返回结果 | 执行完了得有个交代 |
7.释放资源 | 让人回去,连接和找来的人都干活了(一个找人了,一个干活了),让他俩回去 后执行的资源 |
变化:MySQL 5之后的驱动包,可以省略注册驱动的步骤,因为它会自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
1.3 JDBC API详解
1.3.1 DriverManager(驱动管理类)
该类在当前使用的方法有
方法 | 功能 |
static void registerDriver(Driver driver) | 使用 DriverManager注册给定的驱动程序 |
static Connection getConnection(String url, String user, String password) | 与url指向的数据库建立连接 |
1.3.1.1 registerDriver
在之前,我们使用:Class.forName("com.mysql.jdbc.Driver");这种反射的形式来注册驱动
按住ctrl点进Driver里,我们会看到
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
在静态代码块中,正是使用了registerDriver方法注册驱动
静态代码块会随着类的加载一起加载,因此只要使用反射加载Driver类即可
1.3.1.2 getConnection
参数说明:
参数 | 含义 | 语法 | 备注 |
url | 连接路径 | jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2… | 1.jdbc:mysql:是“协议”。 2.如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数 据库名称?参数键值对 3.配置 useSSL=false 参数,禁用安全连接方式,解决 警告提示 |
user | 用户名 | \ | 填写数据库用户的用户名 |
password | 密码 | \ | 填写数据库用户的密码 |
1.3.2 Connection(数据库连接对象)
方法 | 功能 |
Statement createStatement() | 获取执行sql的对象 |
void setAutoCommit(boolean autoCommit) | 设置是否自动提交事务 true 自动提交 false 手动提交 |
void commit() | 提交事务 |
void rollback() | 回滚事务 |
事务
回顾:在java中,我们做过关于转账的内容,假设a转账给b,中途发生异常,a掏钱了b却没有得到钱,为了防止这件事的发生,我们需要将这整个转账过程作为一个事务,倘若中途出现异常,则会回滚到最初。
以上方法使用案例:
public static void main(String[] args) throws Exception {
// 2.获取连接
String username = "root";
String password = "123456";
String url = "jdbc:mysql:///test?useSSL=false";
Connection conn = DriverManager.getConnection(url, username, password);
// 3.定义sql
String sql = "UPDATE yuangong SET id = 12333";
String sql1 = "UPDATE yuangong SET yuangongid = 145544";
// 4.获取执行sql的对象
Statement statement = conn.createStatement();
try {
// 开启事务 手动提交事务
conn.setAutoCommit(false);
// 5.执行sql
int count = statement.executeUpdate(sql);//受影响的行数
int i = 3/0;
//6.处理结果
System.out.println(count);
// 提交事务
conn.commit();
} catch (Exception e) {
// 回滚事务
conn.rollback();
e.printStackTrace();
}
// 7.释放资源
statement.close();//后执行的先关闭
conn.close();
}
1.3.3 Statement
方法 | 功能 |
int executeUpdate() | 执行DDL、DML语句,返回执行语句后影响的行数 |
ResultSet executeQuery() | 执行DQL语句,返回ResultSet对象,可以理解为查询出的结果集 |
使用Statement对象调用方法,也就是在JDBC书写中的第5步,执行sql中使用,之前已经有executeUpdate()方法的案例,之后我们会和ResultSet对象一起展示executeQuery()的使用。
1.3.4 ResultSet(结果集对象)
作用:封装了SQL查询语句的结果
方法 | 功能 |
boolean next() | 将光标从当前位置向前移动一行并且判断当前行是否为有效行, 返回值true : 有效行,当前行有数据 |
xxx getXxx(参数) | xxx : 数据类型;如: int getInt(参数) ;String getString(参数) 参数 int类型的参数:列的编号,从1开始 String类型的参数: 列的名称 |
案例:
假设有这样一个表格
姓名 | 年龄 |
桂小太郎 | 27 |
让基尔希斯坦 | 19 |
想要得到参数姓名可以写getString("姓名"),也可写getString(1);
参数类型一定是存放的数据的类型,“姓名”是表头,“1”是姓名的顺序排第一个
使用案例:
//创建一个集合
List<Account> list = new ArrayList<>();
// 1.光标向下移动一行,并判断当前行是否有数据
while (resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
double money = resultSet.getDouble("money");
//不论写数字还是表头名,结果都是一样的
// 1.新建一个account对象
Account account = new Account();
//将结果存放进account对象里
account.setId(id);
account.setName(name);
account.setMoney(money);
list.add(account);
}
1.3.5 PreparedStatement
功能:预编译SQL语句并执行,预防SQL注入问题
1.3.5.1 SQL注入
定义:SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。
案例:
假设在登录场景中,我不知道某个人的密码是多少,通过sql注入强行登录
判断用户能否登录的sql语句为:
String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
也就是在用户表中查询全部信息,当用户名等于name,密码等于pwd的时候,这里的name和pwd都是变量名,相当于是接收用户传来的信息
在这种情况下,我如果将pwd写成:
String pwd = "' or '1' = '1";
那么sql语句就会变为
select * from tb_user where username = 'sjdljfld'and password = ''or '1' = '1';
由于and比or先执行,所以 username = 'sjdljfld'and password = '' 用户名随便乱写and密码为空字符串判断为false,or '1' = '1'恒成立,结果为true,将强行登录
这就是sql注入
1.3.5.2 PreparedStatement使用
方法 | 功能 |
PreparedStatement prepareStatement(String sql) | connection的方法,获取 PreparedStatement 对象来操控sql语句 |
void setXxx(参数1,参数2) | 给 ? 赋值 Xxx:数据类型 ; 如 setInt (参数1,参数2) 参数: 参数1: ?的位置编号,从1 开始 参数2: ?的值 |
int executeUpdate() | 执行DDL、DML语句,返回执行语句后影响的行数 无需传递sql语句,因为获取SQL语句执行对象时已经对SQL语句进行预编译了。 |
ResultSet executeQuery() | 执行DQL语句,返回ResultSet对象,可以理解为查询出的结果集 无需传递sql语句,因为获取SQL语句执行对象时已经对SQL语句进行预编译了。 |
想要使用PreparedStatement方法对sql语句的书写格式有要求
案例:
String sql = "select * from user where username =? and password = ?";
也就是说,sql语句中参数必须使用 ? 进行占位
因此想要赋值则需要:
pstmt.setString(1,name); 代表第一个问号传入变量name
pstmt.setString(2,pwd); 代表第二个问号传入变量pwd
案例:
@Test
public void testLogin1() throws Exception {
// 1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.连接数据库
Connection conn = DriverManager.getConnection("jdbc:mysql:///test2?useSSL=false&useServerPrepStmts=true", "root", "123456");
// 用户输入的用户名与密码
String name = "zhangsan";
String password = "123";
// 3.编写sql语句
String sql = "select * from tb_user where username = ? and password = ?";
// 4.创建statement
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(2,password);
ps.setString(1,name);
// 5.执行sql语句
ResultSet rs = ps.executeQuery();
// 6.处理结果
if(rs.next()){//有无数据
System.out.println("登陆成功");
}else{
System.out.println("登录失败");
}
// 7.回收资源
rs.close();
ps.close();
conn.close();
}
为何PreparedStatement能够防止sql注入?
它是将特殊字符进行了转义,转义的SQL如下:
select * from tb_user where username = 'sjdljfld' and password = '\'or \'1\' = \'1'
1.3.5.3 PreparedStatement预编译原理
当Java代码操作数据库时,sql语句发送到MySQL服务器端,MySQL服务端会对sql语句进行如下操作:
1. 检查SQL语句 检查SQL语句的语法是否正确。
2. 编译SQL语句。将SQL语句编译成可执行的函数。
3. 执行SQL语句
检查SQL和编译SQL花费的时间比执行SQL的时间还要长。如果我们只是重新设置参数,那么检查SQL语句和编译SQL语句将不需要重复执行。这样就提高了性能。
开启预编译功能
1.在代码中编写url时需要加上以下参数
useServerPrepStmts=true
2.配置MySQL执行日志(重启mysql服务后生效)
在mysql配置文件(my.ini)中添加如下配置
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
1.4 数据库连接池
1.4.1 数据库连接池概述
定义:数据库连接池是个容器,负责分配、管理数据库连接(Connection)
和java的线程池非常类似
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;
释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
优点:
- 资源重用
- 提升系统响应速度
- 避免数据库连接遗漏
常见的数据库连接池:DBCP,C3P0,Druid
我们会学习Druid连接池 Druid连接池是阿里巴巴开源的数据库连接池项目
1.4.2 Driud使用
使用步骤:
1.导入jar包 druid-1.1.12.jar
2.定义配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///db1?
useSSL=false&useServerPrepStmts=true
username=root
password=1234
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
3.加载配置文件
4.获取数据库连接池对象
5.获取连接
案例:
Druid数据库连接池演示
public class DruidDemo {
public static void main(String[] args) throwsException {
//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); //获取到了连接后就可以继续做其他操作了
//System.out.println(System.getProperty("user.dir"));
}
}
2 Maven
2.1 概述
官网:http://maven.apache.org/
- 提供了一套标准化的项目结构
- 提供了一套标准化的构建流程(编译,测试,打包,发布……)
- 提供了一套依赖管理机制
记忆:
开发过程中,代码需要进行编译、测试、打包、发布的过程,自己做很麻烦,使用Maven可以快捷的完成【之后就会展示,点击几下就可以,不用我们管】
3.依赖管理:
2.2 Maven模型
- 项目对象模型 (Project Object Model)
- 依赖管理模型(Dependency)
- 插件(Plugin)
我们将Maven模型与功能放在一起来理解记忆
2.2.1 标准化的构建流程 与 插件
代码需要进行编译、测试、打包、发布,这些过程在Maven中使用插件来辅助完成。
2.2.2 依赖管理 与 项目对象模型、依赖管理模型
Maven的依赖管理采用坐标管理的形式,而项目对象模型就是将项目抽象成一个对象模型,有自己专属的坐标
案例:
MYsql的坐标案例
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
<scope>provided</scope>
</dependency>
项目的坐标案例
<groupId>com.xuexi</groupId>
<artifactId>maven-project</artifactId>
<version>1.0-SNAPSHOT</version>
2.2.3 仓库
Maven使用坐标来快速导入jar包,jar包的来源就是仓库
- 本地仓库:自己计算机上的一个目录
- 中央仓库:由Maven团队维护的全球唯一的仓库 地址: https://repo1.maven.org/maven2/
- 远程仓库(私服):一般由公司团队搭建的私有仓库
2.3 Maven安装与配置简述
1.下载apache-maven-x.x.rar,并解压
2.配置环境变量MAVEN_HOME 为安装路径的bin目录
3.配置本地仓库:修改 conf/settings.xml 中的<localRespository>为一个指定目录作为本地仓库,用来存储jar包。
4.配置阿里云私服:修改 conf/settings.xml 中的<mirror> 标签
2.3.1 在IDEA中配置,使用Maven概述
1.配置Maven环境: