里面的数据库连接池所需要的jar包可以在这里面下载:
https://blog.csdn.net/m0_49647974/article/details/115287069
Java 数据库连接,Java语言操作数据库
JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
(1)导入驱动jar包 如:mysql-connector-java-5.1.37-bin.jar
(2)注册驱动
(3)获取数据库连接对象connection4.
(4)定义sql
(5)获取执行sql语句的对象statement6.
(6)执行sq1,接受返回结
(7)处理结果
(8)释放资源
/**
* @Auther: Parsifal
* @Date: 2021/03/22/20:04
* @Description:
*/
public class JDBCTest {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
//1、导入驱动jar包
//2、注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//3、获取数据库连接对象
String userName = "root";
String password = "root";
//报错一:The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to util
// 解决方法与原因:当mysql和connector版本八以上时,系统时区错误,需要在配置连接数据库的url加上:?serverTimezone=GMT%2B8
// 报错二: javax.net.ssl.SSLException: closing inbound before receiving peer's close_notify
//解决方法:需要在配置连接数据库的url加上: &useSSL=false
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useSSL=false", userName, password);
//4、定义sql语句
String sql = "SELECT * FROM student";
//5、获取执行sql的对象、Statement
statement = connection.createStatement();
boolean execute = statement.execute(sql);
//6、处理结果
System.out.println(execute);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
//7、关闭资源
if (statement!=null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection!=null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
但是我们一般都会把这些代码封装成一个Util,把数据库信息写在配置文件里面,如下:
/**
* @Auther: Parsifal
* @Date: 2021/03/24/21:24
* @Description:
*/
public class JDBCUtil {
private static String url;
private static String user;
private static String password;
private static String driver;
//静态模块会在类加载时执行
static {
FileInputStream fileInputStream = null;
try {
//properties处理属性文件
//获取src路径下的文件的方式一(stream)
Properties properties = new Properties();
fileInputStream = new FileInputStream("jdbc.properties");
//加载流对应的文件
properties.load(fileInputStream);
//获取src路径下的文件的方式二(path)
/* ClassLoader classLoader = JDBCUtil.class.getClassLoader();
URL resource = classLoader.getResource("jdbc.properties");
String path = resource.getPath(); //获取绝对路径
System.out.println(path);
properties.load(new FileReader(path));*/
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
driver = properties.getProperty("driver");
Class.forName(driver);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (fileInputStream!=null){
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static Connection getConnection(){
try {
return DriverManager.getConnection(url,user,password);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
//关闭资源
public static void close(Statement statement, Connection connection, ResultSet resultSet){
if (statement!=null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection!=null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
if (resultSet!=null){
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
//关闭资源 重载方法
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();
}
}
}
}
jdbc.properties配置文件
url=jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useSSL=false
user=root
password=root
driver=com.mysql.cj.jdbc.Driver
static void registerDriver(Driver driver) :注册与给定的驱动程序 DriverManager 。
写代码使用: class.forName(“com.mysql.jdbc.Driver”); 把此类加载进内存。
(注意:在mysql5之后的驱动jar包可以省略注册驱动的步骤)
在com.mysql.jdbc.Driver类中存在以下静态代码块,在类加载时运行创建Driver类。
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
方法:DriverManager.getConnection(“jdbc:mysql://localhost:3306/test”, userName, password);
参数:
url:指定连接路径 : jdbc:mysql:// ip地址(域名): 端口 /数据库名称
用 " ?"在url后边可以添加属性,”&”可以连接不同的属性,以下举例一些属性:
serverTimezone=GMT mysql8版本以上要加上,作用为调整时区
allowMultiQueries=true,支持mybatis执行多条语句;
useSSL=false,是否进行ssl连接,高版本可能需要设为true;
serverTimezone=UTC,设置时区
uersName:用户名称,password:密码。
注意如果是本机mysql服务器,并且mysql服务默认端口为3306,则url可以不写(jdbc:mysql:///test)
事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败
为什么要使用事务?
首先我们先了解没有事务的时候:如果不通过事务方式管理SQL语句。此时的SQL语句的提交(commit),是由驱动程序负责管理,在SQL执行完后,就会自动帮我们进行提交,每一条SQL都相当于一个事务。但是执行多条相关联SQL语句,而不通过事务来管理时。如果再某些步骤中中止或操作失误,就会破坏数据库的一致性。(如下,由于没有通过事务sql,我有两条sql语句修改两个内容,当第一条语句执行完后,中间遇到步骤终止和操作失误,会导致第二条sql无法执行。这是很严重的后果。)
步骤:
//JDBC事务
@Test
public void test2(){
Connection connection = null;
Statement statement = null;
PreparedStatement preparedStatement1 =null;
PreparedStatement preparedStatement2 =null;
try {
//获取连接
connection = JDBCUtil.getConnection();
//开启事务
connection.setAutoCommit(false);
//修改id=1的学生的绩点
String sql1 = " update student set name='张三' where id= ? ";
//修改id=2的学生的绩点
String sql2 = "update student set name='李四' where id= ? ";
preparedStatement1 = connection.prepareStatement(sql1);
preparedStatement2 = connection.prepareStatement(sql2);
preparedStatement1.setInt(1,1);
preparedStatement2.setInt(1,2);
preparedStatement1.executeUpdate();
//手动制造异常
// int a =1/0;
preparedStatement2.executeUpdate();
//提交事务
connection.commit();
} catch (Exception throwables) {
try {
//事务的回滚
if (connection!=null) {
connection.rollback();
}
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
} finally {
JDBCUtil.close(preparedStatement1, connection);
if (preparedStatement2!=null) {
try {
preparedStatement2.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
没有使用事务(两条语句中间手动制造异常,第一条语句执行)
常用方法:
作用: 预编译sql语句防止恶意sql注入
SQL注入问题∶在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
使用方法:
(1)使用 ?占位符写sql(如 :select * from student where id = ?and grade=?)
(2)获取执行sql语句的对象Preparedstatement Connection.prepareStatement(String sql)
(3)给?赋值:格式preparedstatement.setXxx(参数1,参数2) ==>参数1:?的位置,参数2:?的值
@Test
public void test1(){
Connection connection = null;
PreparedStatement preparedStatement =null;
try {
connection = JDBCUtil.getConnection();
//使用 ?占位符写sql
String sql = "select * from student where id = ? and grade=? ";
//给?赋值
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,1);
preparedStatement.setFloat(2,3.5f);
ResultSet resultSet = preparedStatement.executeQuery();
//处理结果
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String email = resultSet.getString("email");
double grade = resultSet.getDouble("grade");
System.out.println(id + name + email + grade); //结果:1 zzz [email protected] 3.5
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtil.close(preparedStatement, connection);
}
}
概念::其实就足一个容器(集合),存放数据库连接的容器。当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
好处:
实现:
/**
* @Auther: Parsifal
* @Date: 2021/03/27/20:38
* @Description: C3P0的演示
*/
public class C3P0Test {
public static void main(String[] args) throws SQLException {
// 1、创建数据库连接池对象 ->使用默认配置
// DataSource ds = new ComboPooledDataSource();
//使用指定配置
DataSource ds = new ComboPooledDataSource("otherc3p0");
// 2、获取连接对象
Connection conn = ds.getConnection();
System.out.println(conn);
conn.close();
}
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driverproperty>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useSSL=falseproperty>
<property name="user">rootproperty>
<property name="password">rootproperty>
<property name="initialPoolSize">5property>
<property name="maxPoolSize">10property>
<property name="checkoutTimeout">3000property>
default-config>
<named-config name="otherc3p0">
named-config>
c3p0-config>
实现代码:
package DateSource;
import DateSource.Druid.DruidTest;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* @Auther: Parsifal
* @Date: 2021/03/27/22:22
* @Description: 使用Druid数据库连接池的JDBCUtil
*/
public class JDBCUtil {
static DataSource ds;
static {
//加载配置文件
try {
//1、导入jar包
//2、定义配置文件
//3、加载配置文件 不可以默认配置文件 ,必须指定文件
Properties properties =new Properties();
InputStream is = DruidTest.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(is);
//4、获取数据库连接池对象
ds = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
/**
* 关闭资源
* @param resultSet
* @param statement
* @param connection
*/
public static void close(ResultSet resultSet, Statement statement, Connection connection){
if (resultSet!=null){
try {
resultSet.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();
}
}
}
/**
* 重载
* @param statement
* @param connection
*/
public static void close(Statement statement ,Connection connection){
close(null,statement,connection);
}
/**
* 获取数据库连接池
* @return
*/
public static DataSource getDataSource(){
return ds;
}
}
spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发步骤︰
步骤:
导入四个jar包 spring-tx-5.0.5.RELEASE.jar spring-jdbc-5.0.5.RELEASE.jar spring-core-5.0.5.RELEASE.jar spring-beans-5.0.5.RELEASE.jar commons-logging-1.2.jar
创建JdbcTemplate对象。依赖于数据源Datasource
调用JdbcTemplate的方法来完成CRUD的操作
update():执行DML语句。增、删、改语句
queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value将这条记录封装为一个map集合
queryForList():查询结果将结果集封装为list集合
query():查询结果,将结果封装为javaBean对象
query的参数:RowMapper
queryForobject :查询结果,将结果封装为对象
/**
* @Auther: Parsifal
* @Date: 2021/03/28/14:12
* @Description:
*/
public class JDBCTemplateTest {
//1、导入jar
//2、创建JDBCTemplate对象
static JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtil.getDataSource());
//查询所有的记录用List集合
@Test
public void test(){
String sql = "select * from student";
//自定义接口
List<Student> students = jdbcTemplate.query(sql, new RowMapper<Student>() {
@Override
public Student mapRow(ResultSet resultSet, int i) throws SQLException {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String email = resultSet.getString("email");
float grade = resultSet.getFloat("grade");
Student student = new Student(id,name,email,grade);
return student;
}
});
students.forEach(System.out::println);
}
//查询所有的记录用List集合
@Test
public void test1(){
String sql = "select * from student";
//使用封装好的接口
List<Student> students = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Student>(Student.class));
students.forEach(System.out::println);
}
}
mysql版本号为8.0.13
解决方法与原因:配置连接数据库的url错误,在后面加上&useSSL=false即可
The server time zone value ‘Öйú±ê׼ʱ¼ä’ is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to util
解决方法与原因:当mysql和connector版本八以上时,系统时区错误,需要在配置连接数据库的url加上:?serverTimezone=GMT%2B8
解决方法与原因:配置文件的url错误(并且注意:&需要转义为&)
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useSSL=falseproperty>
顺便说一下:可以试试看其他的解决方法:
重启mysql服务
<property name="checkoutTimeout">3000property> 改大等待时间
<property name="maxPoolSize">10property> 改小最大连接数量