【黑马Java笔记+踩坑】JavaWeb基础——JDBC
目录
JDBC
JDBC概述
JDBC概念
JDBC本质
JDBC好处
JDBC步骤
标准代码
编写代码步骤
获取数据库连接的各种方式
JDBC所有API
驱动管理类 DriverManager
数据库连接对象Connection
获取执行对象
事务管理
Statement
结果集对象 ResultSet
SQL注入
PreparedStatement
PreparedStatement原理
数据库连接池DataSource
数据库连接池简介
数据库连接池实现
Driud下载
Driud使用
Druid配置文件详解
JDBC练习
需求:完成商品品牌数据的增删改查操作
案例实现
JDBC
JDBC概述
JDBC概念
了解即可,后面都用Mybatis框架。MyBatis是一个持久层ORM框架,底层是对JDBC的封装。
JDBC是Java提供的一个操作数据库的API;
全称:( Java DataBase Connectivity ) Java 数据库连接
为什么要用jdbc?
我们开发的同一套Java代码是无法操作不同的关系型数据库,因为每一个关系型数据库的底层实现细节都不一样。为了解决这个问题,JDBC中定义了所有操作关系型数据库的规则(接口)。
众所周知接口是无法直接使用的,我们需要使用接口的实现类,而这套实现类(称之为:驱动)就由各自的数据库厂商给出。
JDBC本质
官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口
各个数据库厂商去实现这套接口,提供数据库驱动jar包
我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类
JDBC好处
各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发
可随时替换底层数据库,访问数据库的Java代码基本不变
以后编写操作数据库的代码只需要面向JDBC(接口),操作哪儿个关系型数据库就需要导入该数据库的驱动包,如需要操作MySQL数据库,就需要再项目中导入MySQL数据库的驱动包。如下图就是MySQL驱动包:
JDBC步骤
通过Java操作数据库的流程:
第一步:编写Java代码
第二步:Java代码将SQL发送到MySQL服务端
第三步:MySQL服务端接收到SQL语句并执行该SQL语句
第四步:将SQL语句执行的结果返回给Java代码
标准代码
jdbc整个技术点了解即可,后面更多用Mybatis框架简化了jdbc开发,Mybatis整合spring后代码还有改变。
剧透Mybatis:下一章详细讲,现在看看就行
JavaWeb基础3——Maven&MyBatis_vincewm的博客-CSDN博客
public class Demo {public static void main(String[] args) throws IOException {//1. 加载mybatis的核心配置文件,获取 SqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2. 获取SqlSession对象,用它来执行sqlSqlSession sqlSession = sqlSessionFactory.openSession();//3. 执行sql//参数是一个字符串,该字符串必须是映射配置文件的namespace.id // List<User> users = sqlSession.selectList("test.selectAll");//3.1获取UserMapper接口的代理对象UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//3.2调用sql方法List<User> users = userMapper.selectAll();System.out.println(users);//4. 释放资源sqlSession.close();} }
简单版:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;/*** 简单版*/
public class Demo {public static void main(String[] args) throws Exception {//1. 注册驱动//Class.forName("com.mysql.jdbc.Driver");//通过反射获取Driver实现类对象,从而加载驱动,注册驱动语句DriverManager.registerDriver(driver)在Driver的静态代码块里做过了。//此句仅在mysql可省略,其他数据库不能省略//2. 获取连接String url = "jdbc:mysql://127.0.0.1:3306/db1?useSSL=false";String username = "root";String passWord = "1234";Connection conn = DriverManager.getConnection(url, username, passWord);//3. 定义sqlString sql = "update student set age = 80 where name='xiaohua'";//4. 获取执行sql的对象 StatementStatement stmt = conn.createStatement();//5. 执行sqlint count = stmt.executeUpdate(sql);//受影响的行数//6. 处理结果System.out.println(count);//7. 释放资源stmt.close();conn.close();}
}
优化版,Properties和PreparedStatement:
import java.io.FileReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.util.Properties;/*** 优化版*/
public class Demo {public static void main(String[] args) throws Exception {Properties prop=new Properties();//System.out.println(System.getProperty("user.dir")); //获取当前路径FileReader fileReader = new FileReader("module2/src/jdbc.properties");prop.load(fileReader);//1. 注册驱动
// Class.forName(prop.getProperty("driverClass"));//2. 获取连接String url = prop.getProperty("url");String username = prop.getProperty("username");String password = prop.getProperty("password");Connection conn = DriverManager.getConnection(url, username, password);//3. 定义sql//4. 获取执行sql的对象 StatementPreparedStatement pstmt = conn.prepareStatement("update student set age = ? where name=?"); //PreparedStatement防止sql注入pstmt.setInt(1,30);pstmt.setString(2,"xiaoming");//5. 执行sqlint count = pstmt.executeUpdate();//受影响的行数//6. 处理结果System.out.println(count);//7. 释放资源pstmt.close();conn.close();}
}
#jdbc.properties
username=root
password=1234
url=jdbc:mysql://127.0.0.1:3306/db1
driverClass=com.mysql.jdbc.Driver
编写代码步骤
0.导入驱动jar包。
为什么要导包?
因为jdbc本质是关系型数据库接口,需要导入数据库的实现类的包才能连接数据库。
方法:将mysql的驱动包放在模块下的lib目录(随意命名)下,右键add as library,也就是将该jar包添加为库文件,选择模块有效,name为空就行。
地址:MySQL :: Download Connector/J,选择Platform Independent。
在添加为库文件的时候,有如下三个选项
Global Library : 全局有效
Project Library : 项目有效
Module Library : 模块有效
1.加载并注册驱动
Class.forName("com.mysql.jdbc.Driver"); //把mysql的驱动类Driver的对象加载进内存并初始化
驱动类Driver 的方法:
static 类<?>
forName(String className)
返回与给定字符串名称的类或接口相关联的
类
对象。
Class.forName 方法的作用,就是初始化给定的类。
而我们给定的 MySQL 的 Driver 类中,它在静态代码块中通过 JDBC 的 DriverManager 注册了一下驱动。我们也可以直接使用 JDBC 的驱动管理器DriverManager 注册 mysql 驱动,从而代替使用 Class.forName。
DriverManager.registerDriver(new Driver());
2.获取连接(获取java与mysql服务端之间的连接)
Connection conn = DriverManager.getConnection(url, username, password);
驱动管理器类DriverManager的方法:
static Connection
getConnection(String url, String user, String password)
尝试建立与给定数据库URL的连接。
Java代码需要发送SQL给MySQL服务端,就需要先建立连接
3.定义SQL语句
String sql = “update…” ;
4.获取执行SQL对象
执行SQL语句需要SQL执行对象,而这个执行对象就是Statement对象
Statement stmt = conn.createStatement();
5.执行SQL(把SQL语句发送到mysql服务器,mysql服务器执行SQL语句)
stmt.executeUpdate(sql);
6.java处理返回结果
7.释放资源
获取数据库连接的各种方式
Connection
connect(String url, Properties info)
尝试使数据库连接到给定的URL。
方法一:通过Driver对象获取:
Driver driver=new com.mysql.jdbc.Driver(); //多态语句,driver是Driver接口对象,com.mysql.jdbc.Driver()是mysql的实现类String url="jdbc:mysql://127.0.0.1:3306/db1"; //jdbc是主协议,mysql是子协议,主协议:子协议://ip地址:端口/数据库名Properties info=new Properties();info.setProperty("user","root");info.setProperty("password","1234");Connection conn=driver.connect(url,info);
方法二:通过反射获取:
Class c=Class.forName("com.mysql.jdbc.Driver"); //通过反射,获取Driver实现类对象cDriver driver=(Driver) c.newInstance(); //调用类对象c的构造方法,实现构造方法对象driver的创建String url="jdbc:mysql://127.0.0.1:3306/db1"; //jdbc是主协议,mysql是子协议,主协议:子协议://ip地址:端口/数据库名Properties info=new Properties();info.setProperty("user","root");info.setProperty("password","1234");Connection conn=driver.connect(url,info);
方法三:DriverManager替代Driver
DriverManager方法:
static void
registerDriver(Driver driver)
注册与给定的驱动程序
DriverManager
。static Connection
getConnection(String url, String user, String password)
尝试建立与给定数据库URL的连接。
方法四:可以只是加载驱动,注册驱动在mysql的Driver实现类静态代码块里做过了,故可以省略相关语句。
//1. 注册驱动
// Class.forName("com.mysql.jdbc.Driver");//2. 获取连接String url = "jdbc:mysql://127.0.0.1:3306/db1";String username = "root";String passWord = "1234";Connection conn = DriverManager.getConnection(url, username, passWord);
方法五:
src下新建jdbc.properties:
JDBC所有API
驱动管理类 DriverManager
作用:注册驱动和获取数据库连接
注册驱动方法:
而在实际连接数据库的时候并不需要registerDriver,因为mysql的Driver实现类里有静态代码块已经registerDriver过了:
因此我们只需要加载 Driver
类进内存,该静态代码块就会执行:
// 将类Driver加载到内存,在内存会产生一个和类Driver对应的Class实例
Class class = Class.forName("com.mysql.jdbc.Driver");
提示:mysql加载Driver类方法可以省略
MySQL 5之后的驱动包,可以省略注册驱动的步骤
自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
DriverManager类,获取数据库连接方法:
url : 连接路径
语法:主协议jdbc:子协议mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2…
示例:jdbc:mysql://127.0.0.1:3306/db1
jdbc:mysql://localhost:3306/db1
细节:
如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称?参数键值对,示例:jdbc:mysql:///db1
配置 useSSL=false 参数,禁用安全连接方式,解决警告提示,示例:jdbc:mysql://127.0.0.1:3306/db1?useSSL=false
数据库连接对象Connection
//4. 获取执行sql的对象 StatementStatement stmt = conn.createStatement();//Statement对象:用于执行静态SQL语句并返回其生成的结果的对象。
Connection(数据库连接对象)作用:
获取执行 SQL 的对象
管理事务
获取执行对象
普通执行SQL对象
Statement createStatement() //
标准代码中就是通过该方法获取的执行对象。
预编译SQL的执行SQL对象:防止SQL注入
PreparedStatement prepareStatement(sql)
通过这种方式获取的
PreparedStatement
SQL语句执行对象是我们一会重点要进行讲解的,它可以防止SQL注入。执行存储过程的对象
CallableStatement prepareCall(sql)
通过这种方式获取的
CallableStatement
执行对象是用来执行存储过程的,而存储过程在MySQL中不常用,所以这个我们将不进行讲解。
事务管理
先回顾一下MySQL事务管理的操作:
开启事务 : BEGIN; 或者 START TRANSACTION;
提交事务 : COMMIT;
回滚事务 : ROLLBACK;
MySQL默认是自动提交事务
可以通过下面语句查询默认提交方式:
SELECT @@autocommit;查询到的结果是1 则表示自动提交,结果是0表示手动提交。当然也可以通过下面语句修改提交方式
set @@autocommit = 0;
接下来学习JDBC事务管理的方法。
Connection几口中定义了3个对应的方法:
开启事务
参与autoCommit 表示是否自动提交事务,true表示自动提交事务,false表示手动提交事务。而开启事务需要将该参数设为为false。
提交事务
回滚事务
具体代码实现如下:
/*** JDBC API 详解:Connection*/
public class JDBCDemo3_Connection {public static void main(String[] args) throws Exception {//1. 注册驱动//Class.forName("com.mysql.jdbc.Driver");//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写String url = "jdbc:mysql:///db1?useSSL=false";String username = "root";String passWord = "1234";Connection conn = DriverManager.getConnection(url, username, passWord );//3. 定义sqlString sql1 = "update account set money = 3000 where id = 1";String sql2 = "update account set money = 3000 where id = 2";//4. 获取执行sql的对象 StatementStatement stmt = conn.createStatement();try {// ============开启事务==========conn.setAutoCommit(false);//5. 执行sqlint count1 = stmt.executeUpdate(sql1);//受影响的行数//6. 处理结果System.out.println(count1);int i = 3/0;//5. 执行sqlint count2 = stmt.executeUpdate(sql2);//受影响的行数//6. 处理结果System.out.println(count2);// ============提交事务==========//程序运行到此处,说明没有出现任何问题,则需求提交事务conn.commit();} catch (Exception e) {// ============回滚事务==========//程序在出现异常时会执行到这个地方,此时就需要回滚事务conn.rollback();e.printStackTrace();}//7. 释放资源stmt.close();conn.close();}
}
Statement
Statement对象的作用就是用来执行SQL语句。
String sql = "update student set age = 222 where name='xiaohua'";//4. 获取执行sql的对象 StatementStatement stmt = conn.createStatement();//5. 执行sqlint count = stmt.executeUpdate(sql);//受影响的行数
注意:
以后开发很少使用java代码操作DDL语句
执行DDL、DML语句
DDL:show,create,use,select,drop,alter
DML:insert,update,delete
执行DQL语句
DQL:select,from,where,group by,having,order by,limit
结果集对象 ResultSet
作用:封装了SQL查询语句的结果,执行了DQL语句后就会返回该对象。
回顾Statement执行DQL语句的方法,返回值就是ResultSet对象:
ResultSet executeQuery(sql):执行DQL 语句,返回 ResultSet 对象
方法:
boolean next()
将光标从当前位置向下移动一行,并判断当前行是否为有效行
方法返回值说明:
true : 有效航,当前行有数据
false : 无效行,当前行没有数据
xxx getXxx(参数):获取数据
xxx : 数据类型;如: int getInt(参数) ;String getString(参数)
参数
int类型的参数:列的编号,从1开始
String类型的参数: 列的名称
示例:
import java.io.FileReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;/*** JDBC快速入门*/
public class Demo {public static void main(String[] args) throws Exception {Properties prop=new Properties();FileReader fileReader = new FileReader("module2/src/jdbc.properties");prop.load(fileReader);//1. 注册驱动Class.forName(prop.getProperty("driverClass"));//2. 获取连接String url = prop.getProperty("url");String username = prop.getProperty("username");String password = prop.getProperty("password");Connection conn = DriverManager.getConnection(url, username, password);//3. 定义sqlString sql = "select * from student";//4. 获取执行sql的对象 StatementStatement stmt = conn.createStatement();//5. 执行sqlResultSet resultSet = stmt.executeQuery(sql);while(resultSet.next()){System.out.println(resultSet.getInt("id")+" "+resultSet.getString("name"));}//7. 释放资源stmt.close();conn.close();resultSet.close();}
}
SQL注入
SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。
示例:
这样只需要输入框写入'1' = '1就可以令拼接后sql语句条件判断为true,从而获取到所有用户信息。
详细解释:上面代码是将用户名和密码拼接到sql语句中,拼接后的sql语句如下
从上面语句可以看出条件不管是否满足, or
后面的 '1' = '1'
都是始终满足的,最终条件是成立的,就可以正常的进行登陆了。
PreparedStatement对象可以预防sql注入。
PreparedStatement
作用:预编译SQL语句并执行,预防SQL注入问题。
PreparedStatement pstmt = conn.prepareStatement("update student set age = ? where name=?"); //PreparedStatement防止sql注入pstmt.setInt(1,30);pstmt.setString(2,"xiaoming");
通过这种方式,字符串内容如果有敏感字符,则会转义成符号,从而防止sql注入问题。
获取 PreparedStatement 对象
// SQL语句中的参数值,使用?占位符替代 String sql = "select * from user where username = ? and password = ?"; // 通过Connection对象获取,并传入对应的sql语句 PreparedStatement pstmt = conn.prepareStatement(sql);
设置参数值
上面的sql语句中参数使用 ? 进行占位,在之前之前肯定要设置这些 ? 的值。
PreparedStatement对象:setXxx(参数1,参数2):给 ? 赋值
Xxx:数据类型 ; 如 setInt (1,234)为设置第一个问号值为234
参数:
参数1: ?的位置编号,从1 开始
参数2: ?的值
执行SQL语句
executeUpdate(); 执行DDL语句和DML语句
executeQuery(); 执行DQL语句
==注意:==
调用这两个方法时不需要传递SQL语句,因为获取SQL语句执行对象时已经对SQL语句进行预编译了。
PreparedStatement原理
PreparedStatement 好处:
预编译SQL,性能更高
防止SQL注入:将敏感字符进行转义
PreparedStatement开启预编译功能:
在代码中编写url时需要加上以下参数。不开启预编译的情况下,PreparedStatement对象只是解决了SQL注入漏洞。
useServerPrepStmts=true
为什么预编译性能更高?
MySQL服务器检查SQL和编译SQL花费的时间比执行SQL的时间还要长。如果我们只是重新设置参数,那么检查SQL语句和编译SQL语句将不需要重复执行。这样就提高了性能。
PrepareStatement预编译过程:
在获取PreparedStatement对象时,将sql语句发送给mysql服务器进行检查,编译(这些步骤很耗时)
执行时就不用再进行这些步骤了,速度更快
如果sql模板一样,则只需要进行一次检查、编译
数据库连接池DataSource
数据库连接池简介
数据库连接池是个容器,负责分配、管理数据库连接(Connection)。
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;
释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
好处
资源重用
提升系统响应速度
避免数据库连接遗漏
之前我们代码中使用连接是没有使用都创建一个Connection对象,使用完毕就会将其销毁。这样重复创建销毁的过程是特别耗费计算机的性能的及消耗时间的。
而数据库使用了数据库连接池后,就能达到Connection对象的复用,如下图
连接池是在一开始就创建好了一些连接(Connection)对象存储起来。用户需要连接数据库时,不需要自己创建连接,而只需要从连接池中获取一个连接进行使用,使用完毕后再将连接对象归还给连接池;这样就可以起到资源重用,也节省了频繁创建连接销毁连接所花费的时间,从而提升了系统响应的速度。
数据库连接池实现
标准接口:DataSource
官方(SUN) 提供的数据库连接池标准接口,由第三方组织实现此接口。该接口提供了获取连接的功能:
Connection getConnection()
那么以后就不需要通过 DriverManager
对象获取 Connection
对象,而是通过连接池(DataSource)获取 Connection
对象。
常见的数据库连接池
我们现在使用更多的是Druid,它的性能比其他两个会好一些。
DBCP
C3P0
Druid
Druid(德鲁伊)
Druid连接池是阿里巴巴开源的数据库连接池项目
功能强大,性能优秀,是Java语言最好的数据库连接池之一
Driud下载
下载地址:
Central Repository: com/alibaba/druid
选择版本:
选择jar包:
Driud使用
导入jar包
定义配置文件
加载配置文件
获取数据库连接池对象
获取连接
导入jar包
跟mysql的jar包类似,复制粘贴到模块目录下lib文件夹下,右键add as library,level选择module library
定义配置文件:
在模块下新建druid.properties,编写配置文件,前四句跟jdbc.properties一样。示例:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true
username=root
password=1234# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
加载配置文件:
Properties的load方法。
获取当前路径:
System.out.println(System.getProperty("user.dir"));
获取数据库连接池对象:
使用德鲁伊连接池工厂类DruidDataSourceFactory的创建连接池方法createDataSource获取连接池对象。
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
获取数据库连接 Connection:
Connection connection = dataSource.getConnection();System.out.println(connection); //获取到了连接后就可以继续做其他操作了
代码示例:
/*** Druid数据库连接池演示*/
public class DruidDemo {public static void main(String[] args) throws Exception {//1.导入jar包//2.定义配置文件//3. 加载配置文件Properties prop = new Properties();//System.out.println(System.getProperty("user.dir")); //获取当前路径prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));//4. 获取连接池对象DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);//5. 获取数据库连接 ConnectionConnection connection = dataSource.getConnection();//System.out.println(connection); //获取到了连接后就可以继续做其他操作了}
}
剧透一下spring框架的Jdbc.config配置文件使用druid:
public class JdbcConfig {@Value("${jdbc.driver}")private String driver;@Value("${jdbc.url}")private String url;@Value("${jdbc.username}")private String userName;@Value("${jdbc.password}")private String password;@Beanpublic DataSource dataSource(){DruidDataSource ds = new DruidDataSource();ds.setDriverClassName(driver);ds.setUrl(url);ds.setUsername(userName);ds.setPassword(password);return ds;}//配置事务管理器,mybatis使用的是jdbc事务@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource){DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();transactionManager.setDataSource(dataSource);return transactionManager;} }
对比不使用连接池
//1. 注册驱动//Class.forName("com.mysql.jdbc.Driver");//通过反射获取Driver实现类对象,从而加载驱动,注册驱动语句DriverManager.registerDriver(driver)在Driver的静态代码块里做过了。//此句仅在mysql可省略,其他数据库不能省略//2. 获取连接String url = "jdbc:mysql://127.0.0.1:3306/db1?useSSL=false";String username = "root";String passWord = "1234";Connection conn = DriverManager.getConnection(url, username, passWord);
Druid配置文件详解
配置 | 缺省值 | 说明 |
name |
配置这个属性的意义在于,如果存在多个数据源,监控的时候 可以通过名字来区分开来。如果没有配置,将会生成一个名字, 格式是:"DataSource-" + System.identityHashCode(this) |
|
jdbcUrl |
连接数据库的url,不同数据库不一样。例如: MYSQL : jdbc:mysql://10.20.153.104:3306/druid2 ORACLE : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto |
|
username | 连接数据库的用户名 | |
password |
连接数据库的密码。如果你不希望密码直接写在配置文件中, 可以使用ConfigFilter。详细看这里: 使用ConfigFilter · alibaba/druid Wiki · GitHub |
|
driverClassName | 根据url自动识别 | 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName |
initialSize | 0 | 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 |
maxActive | 8 | 最大连接池数量 |
maxIdle | 8 | 已经不再使用,配置了也没效果 |
minIdle | 最小连接池数量 | |
maxWait |
获取连接时最大等待时间,单位毫秒。配置了maxWait之后, 缺省启用公平锁,并发效率会有所下降, 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 |
|
poolPreparedStatements | false |
是否缓存preparedStatement,也就是PSCache。 PSCache对支持游标的数据库性能提升巨大,比如说oracle。 在mysql5.5以下的版本中没有PSCache功能,建议关闭掉。 作者在5.5版本中使用PSCache,通过监控界面发现PSCache有缓存命中率记录, 该应该是支持PSCache。 |
maxOpenPreparedStatements | -1 |
要启用PSCache,必须配置大于0,当大于0时, poolPreparedStatements自动触发修改为true。 在Druid中,不会存在Oracle下PSCache占用内存过多的问题, 可以把这个数值配置大一些,比如说100 |
validationQuery |
用来检测连接是否有效的sql,要求是一个查询语句。 如果validationQuery为null,testOnBorrow、testOnReturn、 testWhileIdle都不会其作用。 |
|
testOnBorrow | true | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
testOnReturn | false | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
testWhileIdle | false |
建议配置为true,不影响性能,并且保证安全性。 申请连接的时候检测,如果空闲时间大于 timeBetweenEvictionRunsMillis, 执行validationQuery检测连接是否有效。 |
timeBetweenEvictionRunsMillis |
有两个含义: 1) Destroy线程会检测连接的间隔时间 2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明 |
|
numTestsPerEvictionRun | 不再使用,一个DruidDataSource只支持一个EvictionRun | |
minEvictableIdleTimeMillis | ||
connectionInitSqls | 物理连接初始化的时候执行的sql | |
exceptionSorter | 根据dbType自动识别 | 当数据库抛出一些不可恢复的异常时,抛弃连接 |
filters |
属性类型是字符串,通过别名的方式配置扩展插件, 常用的插件有: 监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall |
|
proxyFilters |
类型是List<com.alibaba.druid.filter.Filter>, 如果同时配置了filters和proxyFilters, 是组合关系,并非替换关系 |
JDBC练习
需求:完成商品品牌数据的增删改查操作
查询:查询所有数据
添加:添加品牌
修改:根据id修改
删除:根据id删除
案例实现
环境准备
数据库表
tb_brand
-- 删除tb_brand表 drop table if exists tb_brand; -- 创建tb_brand表 create table tb_brand (-- id 主键id int primary key auto_increment,-- 品牌名称brand_name varchar(20),-- 企业名称company_name varchar(20),-- 排序字段ordered int,-- 描述信息description varchar(100),-- 状态:0:禁用 1:启用status int ); -- 添加数据 insert into tb_brand (brand_name, company_name, ordered, description, status) values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1),('小米', '小米科技有限公司', 50, 'are you ok', 1);
在pojo包下实体类 Brand
/*** 品牌* alt + 鼠标左键:整列编辑* 在实体类中,基本数据类型建议使用其对应的包装类型*/ public class Brand {// id 主键private Integer id;// 品牌名称private String brandName;// 企业名称private String companyName;// 排序字段private Integer ordered;// 描述信息private String description;// 状态:0:禁用 1:启用private Integer status; public Integer getId() {return id;} public void setId(Integer 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 Integer getOrdered() {return ordered;} public void setOrdered(Integer 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;} @Overridepublic String toString() {return "Brand{" +"id=" + id +", brandName='" + brandName + '\'' +", companyName='" + companyName + '\'' +", ordered=" + ordered +", description='" + description + '\'' +", status=" + status +'}';} }
查询所有
/*** 查询所有* 1. SQL:select * from tb_brand;* 2. 参数:不需要* 3. 结果:List<Brand>*/
@Test
public void testSelectAll() throws Exception {//1. 获取Connection//3. 加载配置文件Properties prop = new Properties();prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));//4. 获取连接池对象DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//5. 获取数据库连接 ConnectionConnection conn = dataSource.getConnection();//2. 定义SQLString sql = "select * from tb_brand;";//3. 获取pstmt对象PreparedStatement pstmt = conn.prepareStatement(sql);//4. 设置参数//5. 执行SQLResultSet rs = pstmt.executeQuery();//6. 处理结果 List<Brand> 封装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();
}
添加数据
/*** 添加* 1. SQL:insert into tb_brand(brand_name, company_name, ordered, description, status) values(?,?,?,?,?);* 2. 参数:需要,除了id之外的所有参数信息* 3. 结果:boolean*/
@Test
public void testAdd() throws Exception {// 接收页面提交的参数String brandName = "香飘飘";String companyName = "香飘飘";int ordered = 1;String description = "绕地球一圈";int status = 1;
//1. 获取Connection//3. 加载配置文件Properties prop = new Properties();prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));//4. 获取连接池对象DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);//5. 获取数据库连接 ConnectionConnection conn = dataSource.getConnection();//2. 定义SQLString 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. 执行SQLint count = pstmt.executeUpdate(); // 影响的行数//6. 处理结果System.out.println(count > 0);
//7. 释放资源pstmt.close();conn.close();
}
修改数据
/*** 修改* 1. SQL:
update tb_brandset brand_name = ?,company_name= ?,ordered = ?,description = ?,status = ?where id = ?
* 2. 参数:需要,所有数据* 3. 结果:boolean*/
@Test
public void testUpdate() throws Exception {// 接收页面提交的参数String brandName = "香飘飘";String companyName = "香飘飘";int ordered = 1000;String description = "绕地球三圈";int status = 1;int id = 4;
//1. 获取Connection//3. 加载配置文件Properties prop = new Properties();prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));//4. 获取连接池对象DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);//5. 获取数据库连接 ConnectionConnection conn = dataSource.getConnection();//2. 定义SQLString sql = " update tb_brand\n" +" set brand_name = ?,\n" +" company_name= ?,\n" +" ordered = ?,\n" +" description = ?,\n" +" status = ?\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. 执行SQLint count = pstmt.executeUpdate(); // 影响的行数//6. 处理结果System.out.println(count > 0);
//7. 释放资源pstmt.close();conn.close();
}
删除数据
/*** 删除* 1. SQL:delete from tb_brand where id = ?* 2. 参数:需要,id* 3. 结果:boolean*/
@Test
public void testDeleteById() throws Exception {// 接收页面提交的参数int id = 4;//1. 获取Connection//3. 加载配置文件Properties prop = new Properties();prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));//4. 获取连接池对象DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);//5. 获取数据库连接 ConnectionConnection conn = dataSource.getConnection();//2. 定义SQLString sql = " delete from tb_brand where id = ?";//3. 获取pstmt对象PreparedStatement pstmt = conn.prepareStatement(sql);//4. 设置参数pstmt.setInt(1,id);//5. 执行SQLint count = pstmt.executeUpdate(); // 影响的行数//6. 处理结果System.out.println(count > 0);
//7. 释放资源pstmt.close();conn.close();
}
【黑马Java笔记+踩坑】JavaWeb基础——JDBC相关推荐
- 【黑马Java笔记+踩坑】Maven高级
用于复习快速回顾. Maven基础: JavaWeb基础3--Maven&MyBatis_vincewm的博客-CSDN博客 目录 0,解除端口调用 1,分模块开发 1.1 分模块开发设计 1 ...
- 【黑马Java笔记+踩坑】MyBatisPlus基础
用于复习快速回顾. 目录 1,MyBatisPlus简介 1.1 回顾SpringBoot整合Mybatis 1.2 快速入门,实体类注解总结 1.3 MybatisPlus特性 2,标准数据层开发 ...
- 【Java笔记+踩坑】SpringBoot基础3——开发。热部署+配置高级+整合NoSQL/缓存/任务/邮件/监控
导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud/SpringCloudAlibaba+黑马旅游+谷粒商城 目录 ...
- 【Java笔记+踩坑】SpringBoot基础2——运维实用
导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud/SpringCloudAlibaba+黑马旅游+谷粒商城 目录 ...
- 【Java笔记+踩坑】SpringBoot——基础
导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud/SpringCloudAlibaba+黑马旅游+谷粒商城 目录 ...
- 瑞吉外卖项目笔记+踩坑1——基础功能
导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud/SpringCloudAlibaba+黑马旅游+谷粒商城 目录 1 ...
- 【尚硅谷Java笔记+踩坑】Git(分布式版本控制工具)
用于复习快速回顾 目录 1.Git 1.0.提交项目到GitHub简洁版 1.2.版本控制 1.3.版本控制工具 1.4.Git简史 1.5.Git工作机制 1.6.Git和代码托管中心 2.Git安 ...
- 谷粒商城笔记+踩坑(6)——商品服务-属性及其关联分组
导航: 谷粒商城笔记+踩坑汇总篇_谷粒商城笔记踩坑6_vincewm的博客-CSDN博客 目录 10.商品服务-属性(规格参数和销售属性) 10.1.新增属性时,新增属性和属性分组的关联关系 10 ...
- 学成在线笔记+踩坑(5)——【媒资模块】上传视频,断点续传
导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud+黑马旅游+谷粒商城+学成在线+牛客面试题 目录 5 上传视频 5.1 ...
最新文章
- 用python实现语音的传输功能_用Python打造一款智能语音聊天小软件!
- python流程控制-python之流程控制
- JS-DOM Element方法和属性
- KVM 介绍(7):使用 libvirt 做 QEMU/KVM 快照和 Nova 实例的快照 (Nova Instances Snapshot Libvirt)...
- linux iptables原理详解及使用说明
- hdu 3395(费用流,二分图的最大权匹配)
- 【加法笔记系列】逻辑电路的实现
- 架构师成长之路:如何提升技术掌控力?
- android 多线程断点续传下载 三
- mysql 创建查询 删除_MYSQL数据库查询删除创建企业基本知识
- gearman mysql 扩展_Gearman的安装和使用
- 接口向mapper传参数
- 记录小新pro13 Intel版(S540-13IML)安装hackintosh的一些要点
- SQL Server 双机热备份-实现主从复制
- hdu5285 wyh2000 and pupil
- 计算机网络基础之互联网总结
- 【Linux】uptime命令详解平均负载
- c++ 用 eigen与opencv计算两个向量的夹角,两个向量之间的夹角,向量的朝向
- AVR ATMEGA8(2)
- JavaScript性能优化详解