JavaWeb数据库操作
JDBC简介
JDBC的全称是Java数据库连接(Java Data Base Connectivity),是Java程序操作数据的API,JDBC API主要位于java.sql
包中,
该包定义了一系列访问数据库的接口和类。应用程序可以通过这套API连接到不同的数据库SQLServer MySQL Oracle
,并通过SQL
语句完成对数据库中数据的查询、新增、修改、删除操作。
JDBC连接数据库
JDBC连接数据库的步骤主要分为以下三步:
注册数据库驱动
下载相关jar包,官网:https://mvnrepository.com/
MySQL5.7和MySQL8.0的数据库驱动是不一样的
MySQL5.7的连接地址是com.mysql.jdbc.Driver
MySQL8.0的连接地址是com.mysql.cj.jdbc.Driver
加载数据库驱动,注册到驱动管理器
Class.forName("com.mysql.cj.jdbc.Driver");
构建数据库连接URL
JDBC URL的标准有三部门组成,各个部分之间用冒号分隔。
jdbc:子协议:子名称
三大常用数据库的JDBC URL
MySQL
jdbc:mysql://主机名称:mysql服务端口号/数据库名称?参数=值&参数=值 jdbc:mysql://localhost:3306/test jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8 jdbc:mysql://localhost:3306/test?serverTimezone=UTC
Oracle
jdbc:oracle:thin:@主机名称:oracle服务端口号:数据库名称
jdbc:oracle:thin:@localhost:1521:test
SQLServer
jdbc:sqlserver://主机名称:sqlserver服务端口号:DatabaseName=数据库名称 jdbc:sqlserver://localhost:1433:DatabaseName=test
获取Connection对象
可以调用 DriverManager 类的 getConnection(url,username,password) 方法建立到数据库的连接
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
String user="root";
String password="123456";
Connection connection= DriverManager.getConnection(url,user,password);
System.out.println(connection);
connection.close();
}
使用PreparedStatement完成数据库的增删改查操作
增加
public static void main(String[] args) throws Exception {
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="insert into t_department values(null,'开发部','负责开发工作')";
PreparedStatement pst= conn.prepareStatement(sql);
int len = pst.executeUpdate();
System.out.println(len >0 ? "添加成功" : "添加失败");
pst.close();
conn.close();
}
修改
public static void main(String[] args) throws Exception {
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="update t_department set description='负责修改操作' where did=9";
PreparedStatement preparedStatement = conn.prepareStatement(sql);
int i = preparedStatement.executeUpdate();
System.out.println(i>0 ? "修改成功" : "修改失败");
preparedStatement.close();
conn.close();
}
删除
public static void main(String[] args) throws Exception {
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="delete from t_department where did=9";
PreparedStatement preparedStatement = conn.prepareStatement(sql);
int i = preparedStatement.executeUpdate();
System.out.println(i>0 ? "删除成功" : "删除成功");
preparedStatement.close();
conn.close();
}
查询
public static void main(String[] args) throws Exception {
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="select * from t_department ";
PreparedStatement preparedStatement = conn.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
int did = resultSet.getInt("did");
String name=resultSet.getString("dname");
String desc=resultSet.getString("description");
System.out.println(did+"\t"+name+"\t"+desc);
}
resultSet.close();
preparedStatement.close();
conn.close();
}
public static void main(String[] args) throws Exception {
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="select * from t_department ";
PreparedStatement preparedStatement = conn.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
int did = resultSet.getInt(1);
String name=resultSet.getString(2);
String desc=resultSet.getString(3);
System.out.println(did+"\t"+name+"\t"+desc);
}
resultSet.close();
preparedStatement.close();
conn.close();
}
SQL拼接注入问题
新增SQL语句拼接问题
public static void main(String[] args) throws SQLException {
Scanner input = new Scanner(System.in);
System.out.print("请输入姓名:");
String ename = input.next();//李四
System.out.print("请输入薪资:");
double salary = input.nextDouble();//15000
System.out.print("请输入出生日期:");
String birthday = input.next();//1990-1-1
System.out.print("请输入性别:");
char gender = input.next().charAt(0);//男
System.out.print("请输入手机号码:");
String tel = input.next();//13578595685
System.out.print("请输入邮箱:");
String email = input.next();//[email protected]
input.close();
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="INSERT INTO t_employee(ename,salary,birthday,gender,tel,email,hiredate) VALUES('"+ename+"','"+salary+"','"+birthday+"','"+gender+"','"+tel+"','"+email+"',curdate());";
PreparedStatement preparedStatement = conn.prepareStatement(sql);
int i = preparedStatement.executeUpdate();
System.out.println(i>0 ? "添加成功" : "添加失败");
preparedStatement.close();
conn.close();
}
以上代码拼接sql太麻烦,使用?
public static void main(String[] args) throws SQLException {
Scanner input = new Scanner(System.in);
System.out.print("请输入姓名:");
String ename = input.next();//李四
System.out.print("请输入薪资:");
double salary = input.nextDouble();//15000
System.out.print("请输入出生日期:");
String birthday = input.next();//1990-1-1
System.out.print("请输入性别:");
String gender=input.next();
System.out.print("请输入手机号码:");
String tel = input.next();//13578595685
System.out.print("请输入邮箱:");
String email = input.next();//[email protected]
input.close();
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="INSERT INTO t_employee(ename,salary,birthday,gender,tel,email,hiredate) VALUES(?,?,?,?,?,?,?);";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setObject(1,ename);
pst.setObject(2,salary);
pst.setObject(3,birthday);
pst.setObject(4,gender);
pst.setObject(5,tel);
pst.setObject(6,email);
pst.setObject(7,new Date());
int i = pst.executeUpdate();
System.out.println(i>0 ? "添加成功" : "添加失败");
pst.close();
conn.close();
}
查询SQL语句注入问题
public static void main(String[] args) throws SQLException {
Scanner input = new Scanner(System.in);
System.out.print("请输入eid:");
String eid = input.next();
input.close();
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="select * from t_employee where eid=?";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setObject(1,eid);
ResultSetMetaData metaData = pst.getMetaData();
int columnCount = metaData.getColumnCount();
ResultSet rs = pst.executeQuery();
while (rs.next()){
for(int i=1;i<=columnCount;i++){
System.out.print(rs.getObject(i)+" ");
}
}
rs.close();
pst.close();
conn.close();
}
MySQL操作BLOB类型字段
MySQL中,BLOB是二进制对象,可存储图片。
插入BLOB大数据类型
public static void main(String[] args) throws Exception {
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="insert into t_user values(?,?,?)";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setObject(1,"呆瓜");
pst.setObject(2,"123456");
pst.setObject(3,new FileInputStream("D:\\1\\0.jpg"));
int i = pst.executeUpdate();
System.out.println(i>0 ? "添加成功" : "添加失败");
pst.close();
conn.close();
}
插入图片失败的问题
解决方案一:修改my.ini配置文件 max_allowed_packet变量的值
先停止服务,然后修改my.ini文件,再重启服务
解决方案二:修改字段的数据类型mediumblob
读取BLOB大数据类型
public static void main(String[] args) throws Exception {
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="select * from t_user where username='呆瓜'";
PreparedStatement pst = conn.prepareStatement(sql);
ResultSet rs = pst.executeQuery();
while (rs.next()){
String username = rs.getString(1);
String password = rs.getString(2);
Blob photo = rs.getBlob(3);
InputStream is = photo.getBinaryStream();
OutputStream os = new FileOutputStream("D:\\1\\2.jpg");
byte [] buffer = new byte[1024];
int len = 0;
while((len = is.read(buffer)) != -1){
os.write(buffer, 0, len);
}
System.out.print(username+" "+password+" "+photo);
}
pst.close();
conn.close();
}
批处理
public static void main(String[] args) throws Exception{
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="insert into t_department values(null,?,?)";
PreparedStatement pst = conn.prepareStatement(sql);
for(int i=1;i<=100;i++){
pst.setObject(1,"部门"+i);
pst.setObject(2,"简介"+i);
pst.addBatch();
}
int[] len = pst.executeBatch();
System.out.println("添加成功,共:"+len.length+"条");
pst.close();
conn.close();
}
数据库连接池
- 数据库连接池的基本思想**:就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。
- 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
数据库连接池技术的优点**
1. 资源重用
由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增加了系统运行环境的平稳性。
2. 更快的系统反应速度
数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间
3. 新的资源分配手段
对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置,实现某一应用最大可用数据库连接数的限制,避免某一应用独占所有的数据库资源
4. 统一的连接管理,避免数据库连接泄漏
在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露
DBCP
DBCP 是Apache提供的数据库连接池。tomcat 服务器自带dbcp数据库连接池。速度相对c3p0较快,但因自身存在BUG,Hibernate3已不再提供支持。
C3P0
C3P0 是一个开源组织提供的一个数据库连接池,**速度相对较慢,稳定性还可以。hibernate官方推荐使用
Druid
Druid 是阿里提供的数据库连接池,据说是集DBCP 、C3P0 、Proxool 优点于一身的数据库连接池,但是速度不确定是否有BoneCP快
使用德鲁伊数据库连接池
(1)引入jar包
和引入mysql驱动jar方式一样
(2)编写配置文件
src下加一个druid.properties文件
(3)创建数据库连接池对象
(4)获取连接
public static void main(String[] args) throws Exception {
Properties pro = new Properties();
pro.load(DruidTest.class.getClassLoader().getResourceAsStream("druid.properties"));
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
for(int i=1; i<=10; i++){
//多线程,每一个线程代表一个用户来获取连接
new Thread(){
public void run(){
try {
Connection conn = ds.getConnection();
System.out.println(conn);
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}.start();
}
}
Apache-DBUtils实现CRUD操作
-
commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。
-
API介绍:
- org.apache.commons.dbutils.QueryRunner
- org.apache.commons.dbutils.ResultSetHandler
- 工具类:org.apache.commons.dbutils.DbUtils
QueryRunner类
- QueryRunner类的主要方法:
- 更新
- public int update(Connection conn, String sql, Object… params) throws SQLException:用来执行一个更新(插入、更新或删除)操作。
- …
- 插入
- public T insert(Connection conn,String sql,ResultSetHandler rsh, Object… params) throws SQLException:只支持INSERT语句,其中 rsh - The handler used to create the result object from the ResultSet of auto-generated keys. 返回值: An object generated by the handler.即自动生成的键值
- …
- 批处理
- public int[] batch(Connection conn,String sql,Object[][] params)throws SQLException: INSERT, UPDATE, or DELETE语句
- public T insertBatch(Connection conn,String sql,ResultSetHandler rsh,Object[][] params)throws SQLException:只支持INSERT语句
- …
- 查询
- public Object query(Connection conn, String sql, ResultSetHandler rsh,Object… params) throws SQLException:执行一个查询操作,在这个查询中,对象数组中的每个元素值被用来作为查询语句的置换参数。该方法会自行处理 PreparedStatement 和 ResultSet 的创建和关闭。
public static void main(String[] args) throws Exception {
QueryRunner runner = new QueryRunner();
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="insert into t_department values(null,?,?)";
int len = runner.update(conn, sql, "销售部", "负责销售操作");
System.out.println("添加了第"+len+"条数据");
conn.close();
}
ResultSetHandler接口及实现类
接口的主要实现类:
- BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
- BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
- MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
- MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List
- ScalarHandler:查询单个值对象
public static void main(String[] args) throws Exception {
QueryRunner runner = new QueryRunner();
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="select * from t_department where did=?";
BeanHandler<Department> handler = new BeanHandler<>(Department.class);
Department department = runner.query(conn, sql, handler, 9);
System.out.println(department);
conn.close();
}
public static void main(String[] args) throws Exception {
QueryRunner runner = new QueryRunner();
String url="jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
String sql="select * from t_department where did<?";
BeanListHandler<Department> handler = new BeanListHandler<>(Department.class);
List<Department> department = runner.query(conn, sql, handler, 9);
department.forEach(System.out::println);
conn.close();
}