JDBC技术详解
1.概念:
JDBC(Java Database Connectivity)Java数据库连接
JDBC本质:官方定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包,我们可以使用这套接口进行编程,真正执行的代码时驱动jar包里的实现类
2.JDBC快速入门
package cn.zgq.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class jdbcdemo1 {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db2", "root", "******");
Statement statement = connection.createStatement();
int i = statement.executeUpdate("update department set dep_address='绿藤' where id =3");
System.out.println(i);
statement.close();
connection.close();
}
}
-
导入驱动jar包
复制jar包到lib目录下(自己创建lib),再右键lib,点击add as library.
-
注册驱动
-
获取数据库连接对象
-
定义sql
-
获取执行sql语句的对象 Statement
-
执行sql,接受返回结果
-
处理结果
-
释放资源
3.JDBC详解各个对象
-
DriverManager:驱动管理对象
1.注册驱动:告诉程序该使用哪一个数据库的驱动jar包。
相关方法:static void registerDriver(Driver driver)
代码:Class.forName(“com.mysql.cj.jdbc.Driver”),在com.mysql.jdbc.Driver的代码块里面定义了静态代码块来调用DriverManager的registerManager的方法。
注意:MySQL5之后的驱动jar包可以省略注册驱动的步骤,因为系统会自动读取jar包里META-INF–>services–>java.sql.Driver文件,这个文件定义了用于注册驱动的全类名。(但建议写上,是逻辑更加清楚)
2.获取数据库连接对象:
相关方法:static Connection getConnection(String url,String user,String password)
参数:url:指定连接路径(语法:jdbc:mysql://ip地址:端口号/数据库名称) user:用户名 password:密码
注意:如果连接的是本地的mysql服务器,并且MySQL服务器默认端口号是3306,则url可以简写为:jdbc:mysql:///数据库名称
-
Connection:数据库连接对象
-
获取执行sql的对象
Statement createStatement()
PreparedStatement createStatement()
-
管理事务:
开启事务:setAutoCommit(Boolean autocommit):调用该方法并设置参数为true,即开启事务
提交事务:commit()
回滚事务:rollback()
注意:connection对象会占用资源,应在使用完毕后立即关闭
-
-
Statement:用于执行静态sql,并返回执行结果
-
执行静态sql
ResultSet executeQuery(String sql):
执行DQL(select)语句
int executeUpdate(String sql) :
执行DML(insert,update,delete)语句,DDL(create,alter,drop)语句,返回值为影响的条数,可以用于判断DML语句是否执行成功(如果返回值>0则执行成功,反之则失败)
- ResultSet execute(String sql): 执行DQl(select)语句
注意:statement对象会占用资源,应在使用完毕后立即关闭
-
-
ResultSet:结果集对象,封装的查询的结果集对象
-
获取查询结果
Boolean next();
控制游标纵向移动,以指定要获取数据的行,初始时,next指向表头,使用第一次后指向第一行,以此类推。
返回的Boolean类型值用于判断是否有数据,若返回false证明还有数据,若为false证明无数据,用于遍历resultSet
getXxx(参数):
Xxx代表数据类型,例如:int getInt() 、String getString() 、Double getDouble()。 参数可以为int类型或者string类型
参数有两种类型:int类型代表列的编号,从1开始。如getString(2)代表获取表中指定行的第2列的String类型的数据
String类型代表列的字段名,如getString(“name”)代表获取指定行的name字段的值
注意:获取的ResultSet对象也占用资源,在使用完毕后应关闭它。
-
-
PreparedStatement:执行sql对象(继承了Statement)
-
sql注入问题:在拼接sql时,有一些sql特殊的关键字参与字符串的拼接。会造成安全性问题
-
解决sql注入问题:使用PreparedStatement解决
-
预编译的sql:参数使用 ?作为占位符
-
导入驱动jar包
复制jar包到lib目录下(自己创建lib),再右键lib,点击add as library.
-
注册驱动
-
获取数据库连接对象,
-
定义sql,其中参数使用占位符替代
-
获取执行sql语句的对象 Statement,用connection对象的prepareStatement(String sql),在获取时,需传入sql
-
给sql里面的占位符赋值,方法为getXxx(参数1,参数2),参数1指定位置编号(第几个占位符),参数2为占位符赋值
-
执行sql,接受返回结果
-
处理结果
-
释放资源
-
package cn.zgq.jdbc; import java.sql.*; public class jdbcdemo9 { public static void main(String[] args) throws SQLException { login("张三","zhangsan"); } public static void login(String user,String password) throws SQLException { Connection connection = JDBCUtils.getConnection(); String sql="select * from login where user=? && password=? "; PreparedStatement statement = connection.prepareStatement(sql); statement.setString(1,user); statement.setString(2,password); ResultSet resultSet = statement.executeQuery(); if( ! resultSet.next()){ System.out.println("登录失败,密码或者账户错误"); }else{ System.out.println("欢迎"+resultSet.getString(1)); } JDBCUtils.close(statement,connection,resultSet); } }
-
JDBC工具类:JDBCUtils
目的:将每次都重复的代码抽取出来,简化代码书写
分析:
-
抽取注册驱动
-
抽取一个方法获取连接对象
需求:不想传递参数,还得保证工具类的通用性
解决:配置文件
-
抽取一个方法释放资源
工具类JDBCUtils
package cn.zgq.jdbc;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
static{
try {
/*利用Properties类来读取配置文件的内容,注意此项目的在电脑中的存放位置的路径中可能会存在一些字符无法读取导致FIleNOTFOUNDATION异常,
建议改变一下工作区的在硬盘中的位置
*/
Properties properties = new Properties();
//利用类加载器来动态获取资源的绝对路径
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL resource = classLoader.getResource("jdbc.properties");
String path = resource.getPath();
properties.load(new FileReader(path));
//获取数据并赋值
url=properties.getProperty("url");
user=properties.getProperty("user");
password=properties.getProperty("password");
driver=properties.getProperty("driver");
//调用对应的驱动管理器DriverManager对象
Class.forName(driver);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
//抽取getConnection方法
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
//抽取close方法,用于关闭执行DML操做时占用的资源
public static void close(Statement statement, Connection connection){
if(statement !=null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(connection !=null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//重载close方法,用于关闭用于执行DQL方法时占用的资源
public static void close(Statement statement, Connection connection, ResultSet resultSet){
if(resultSet !=null){
try {
statement.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();
}
}
}
}
配置文件: jdbc.properties
url=jdbc:mysql://localhost:3306/db2
user=root
password=208183
driver=com.mysql.cj.jdbc.Driver
JDBC控制事务
-
使用connection对象进行事务去管理
-
方法:
开启事务:connection.setAutoCommit()
提交事务:connection.commit()
回滚事务:connection.rollback()
数据库连接池
1.数据库连接池
-
概念:其实就是一个容器(集合),存放数据库连接对象,当系统初始化后,容器被创建,容器会申请一些连接对象,当用户访问数据库时,从容器中获取连接对象,用户使用完后,将连接放回容器
-
好处:1.节约资源 2.用户访问高效
-
实现:
-
标准接口:DataSource
-
方法:获取连接:getConnection() 归还连接:connection.close()
-
一般我们不去实现它,而由对应的数据库厂商去实现它
-
常用的c3p0、druid
-
c3p0(C3P0地址:https://sourceforge.net/projects/c3p0/?source=navbar C3P0是一个开源的连接池。)
步骤:
- 导入jar包(两个)c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar
- 定义配置文件:名称:c3p0.properties 或者 c3p0-config.xml 路径:直接将文件放在src目录下即可。
- 创建核心对象:数据库连接池对象 ComboPooleedDataSource
- 获取连接:getConnection()
-
druid
步骤:
- 导入jar包 druid-1.0.9.jar
- 定义配置文件: 是properties形式的,可以叫任意名称,放在任意目录下
- 加载配置文件
- 获取数据库连接池对象:通过工厂类 DruidDataSourceFactory来获取
- 获取连接 getConnection
2.SpringJDBC:JDBC Template
Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化的JDBC开发
步骤:
-
导入jar包 :
-
创建JdbcTemplate对象。依赖于数据源DataSource
JdbcTemplate template = new JdbcTemplate (dstaSource)
-
调用JdbcTemplate对象的方法来完成CRUD的操做
- update:执行DML语句的。增删改语句
- queryForMap():查询结果将结果封装为map集合
- queryForList (): 查询结果将结果封装为list集合
- query():查询结果,将结果封装为JavaBean对象
- queryForObject() :查询结果,将结果封装为对象
package cn.zgq.jdbctemplate;
import cn.zgq.domain.Department;
import cn.zgq.druid.JDBCUtils;
import com.sun.org.apache.xerces.internal.impl.xpath.XPath;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
import java.util.Map;
public class demo2 {
//创建JdbcTemplate对象,并传入通过连接池技术如druid获取的dataSource
private static JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource());
public static void main(String[] args) {
//执行DML语句
// String sql="insert into department values(?,?,?)"
// int update = jdbcTemplate.update(sql, 12, "麻石", "组织部");
// System.out.println(update);
//执行DQL语句,将查询的行结果封装为Map集合,其中数据的字段名为key,字段名的值为value
// String sql="select * from department where id=?";
// Map<String, Object> i = jdbcTemplate.queryForMap(sql, 2);
// System.out.println(i);
//执行DQL语句,将查询的结果封装为List集合,其中list集合中存放Map元素,map中存储了每条数据
// String sql="select * from department where dep_address=? or dep_address= ?" ;
// List<Map<String, Object>> i = jdbcTemplate.queryForList(sql, "平昌","巴中");
// for (Map<String, Object> stringObjectMap : i) {
// System.out.println(stringObjectMap);
// }
// System.out.println("-------"+i);
//执行DQL语句,将查询结果封装为对象,此方法常用于聚合函数的查询
// String sql="select count(dep_name) from department";
// Long query = jdbcTemplate.queryForObject(sql,Long.class);
// System.out.println(query);
/*执行DQL语句,将查询结果的每条数据封装为实现定义好Department对象,再将对象放入list集合中,返回list类对象,其中query的参数中的RowMapper接
口可以自己实现,也可以用jdbcTemplate为我们提供的BeanPropertyRowMapper类。
*/
String sql="select * from department";
List<Department> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Department>(Department.class));
for (Department department : query) {
System.out.println(department);
}
}
}