JDBC详解

2023-03-04 13:05:35 浏览数 (2)

文章目录

    • 1、概述
    • 2、JDBC使用步骤
    • 3、DriverManager
    • 4、Connection
    • 5、Statement
    • 6、ResultSet
    • 7、PreparedStatement
    • 8、数据库连接池
      • 8.1、概述
      • 8.2、数据库连接池的实现
      • 8.3、Druid的使用

1、概述

JDBC概念:

  • JDBC就是使用Java语言操作关系型数据库的API
  • 全称:Java DataBase ConectivityJava数据库连接
  • 正常情况下,一套Java代码不能操作不同的关系型数据库,因为每种数据库底层都不同。JDBC就是为了解决这一问题而出现,一套JDBC代码可以操作MySQL、Oracle、IBM等不同的数据库。
  • JDBC只是定义了一套接口(也就是规则),具体的实现类由不同的数据库厂商自己定义,厂商们将实现类称为驱动

JDBC本质:

  • 官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口
  • 各个数据库厂商去实现这套接口,提供数据库驱动jar包,我们需要使用哪个数据库就要再项目导入对应的jar包。
  • 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

JDBC好处:

  • 我们通过一套Java代码可以操作不同的数据库。
  • 可以随时替换底层数据库,访问数据库的Java代码基本不变。

2、JDBC使用步骤

代码语言:javascript复制
public class JDBC {
    public static void main(String[] args) throws Exception {
        // 1. 注册驱动,此步骤在MySQL5.0版本后可省,因为在lib/META-INF/services/java.sql.Driver文件里记录了驱动的名称,会自动加载。
        Class.forName("com.mysql.Driver");

        // 2.获取连接
        String url = "jdbc:mysql://ip地址(域名)/端口号/数据库名称[?参数键值对1&参数键值对2]";
        // String url = "jdbc:mysql://ip地址(域名)/端口号/数据库名称?useSSl=false"解决控制栏警告提示
        String username = "数据库账户名";
        String password = "数据库密码";
        Connection connection = DriverManager.getConnection(url,username,password);

		// 此处可开启事务

        // 3.定义sql
        String sql = "update account set money = 20000 where id = 1";

        // 4.获取执行sql的对象 statement
        Statement statement = connection.createStatement();

        // 5.执行sql
        int count = statement.executeUpdate(sql);

        // 6.处理结果
        System.out.println(count);

		// 此处可提交事务

        // 7.释放资源
        statement.close();
        connection.close();


    }
}

3、DriverManager

DriverManager(驱动管理类)作用:

  • 注册驱动: Class.forName("com.mysql.Driver") 此步骤在MySQL5.0版本后可省略,因为在lib/META-INF/services/java.sql.Driver文件里记录了驱动的名称,会自动加载。
  • 获取数据库连接: Connection connection = DriverManager.getConnection(url,username,password);
    • 其中url="jdbc:mysql://ip地址(域名)/端口号/数据库名称?参数键值对1&参数键值对2"
    • 若连接的是本机MySQL服务器,并且MySQL默认端口是3306,则俩可以简写为:jdba:mysql:///数据库名称[?参数键值对1,参数键值对2]
    • 在域名后面添加useSSl=false参数,禁用安全连接方式,解决控制栏警告提示。 jdbc:mysql://ip地址(域名)/端口号/数据库名称?useSSl=false

4、Connection

Connection(数据库连接对象)作用:

获取执行sql的对象

  • 普通执行sql对象:Statement createStatement()
  • 预编译sql的执行失去了对象:防止sql注入:PreparedStatement prepareStatement(sql)
  • 执行存储过程的对象:CallableStatement prepareCall(sql)

管理事务

  • MySQL事务管理
代码语言:javascript复制
开启事务:BEGIN或START TRANSACTION;
提交事务:COMMIT
回滚事务:ROLLBACK
  • JDBC事务管理:Connection接口中定义了3个对应的方法,默认自动提交事务。
代码语言:javascript复制
开启事务:setAutoCommit(true/false),true为自动提交,false为手动提交,即开启事务
提交事务:commit
回滚事务:rollback

开启事务在定义sql之提交事务在处理完数据库返回的结果回滚事务catch中进行,用try-catch处理sql语句,若出现异常则进行相应的回滚操作。 示例:

代码语言:javascript复制
	try{
		// 开启事务
		connection.setAutoCommit(fale);
		
		// 定义sql
    	String sql = "update account set money = 20000 where id = 1";

    	// 获取执行sql的对象 statement
   		Statement statement = connection.createStatement();

    	// 执行sql
    	int count = statement.executeUpdate(sql);

    	// 处理结果
    	System.out.println(count);

		// 提交事务
		connection.commit();
		} catch(Exception throwables){
			// 回滚事务
			connection.rollback();
		}

5、Statement

Statement作用:执行sql语句

  • int executeUpdate(sql):执行DML(对表的操作)、DDL(对数据的增删改)。 返回值:
    • DML语句影响的行数
    • DDL语句执行后,执行成功也可能返回0
  • ResultSet executeQuery(sql):执行DQL(select查询语句)。 返回值:ResultSet结果集对象

6、ResultSet

ResultSet(结果集对象)作用:

  • 封装了DQL查询语句的结果:ResultSet statement.executeQuery(sql);执行select语句,返回ResultSet对象

获取查询结果:

  • boolean next()
    • 将光标从当前位置向前移动一行。默认指向的表头行,非数据行;因而要获取数据需要将游标往下移动一行
    • 判断当前行是否为有效行
    • 返回值:
      • 有效行,当前行由数据
      • 无效行,当前行无数据
  • xxx getXxx(参数):获取数据,参数可以是具体的值,也可以是对应的字段。
    • xxx:数据类型。如:int getInt(参数);String getString(参数)
    • int:列的编号(主键),从1开始。
    • String:列的名称

我们查询出来的数据需要封装到ArrayList集合中,返回给前端,见以下案例:

需求:查询Account账户表数据,并将数据封装Account对象中,再将Account对象存入ArrayList集合。

创建Account实体类:

代码语言:javascript复制
public class Account {
	private in id;
	private String name;
	private double money;

	public in getId(){
		return id;
	}

	public void setId(int id){
		this.id=id;
	}

	public String getName(){
		return name;
	}

	public void setName(){
		this.name=name;
	}
	
	public double getMoney(){
		return name;
	}

	public void setMoney(){
		this.money=money;
	}

	//这里只是为了查看效果
	@Override
	public String toString(){
		return "Account{" "id="id ",name='" name ''' ",money="money '}';
	}
}

JDBC,查询Account账户表数据,并将数据封装Account对象中,再将Account对象存入ArrayList集合

代码语言:javascript复制
// 1.定义实体类Account
// 2.查询数据,封装到Account对象中
// 3.将Account对象存入ArrayList集合中

public class resultSet() {
    public static void main(String[] args) throws Exception {
        // 1. 注册驱动,此步骤在MySQL5.0版本后可省,因为在lib/META-INF/services/java.sql.Driver文件里记录了驱动的名称,会自动加载。
        Class.forName("com.mysql.Driver");

        // 2.获取连接
        String url = "jdbc:mysql://ip地址(域名)/端口号/数据库名称[?参数键值对1&参数键值对2]";
        // String url = "jdbc:mysql://ip地址(域名)/端口号/数据库名称?useSSl=false"解决控制栏警告提示
        String username = "数据库账户名";
        String password = "数据库密码";
        Connection connection = DriverManager.getConnection(url,username,password);

        // 3.定义sql
        String sql = "select * from account";

        // 4.获取执行sql的对象 statement
        Statement statement = connection.createStatement();

        // 5.执行sql
        ResultSet res = statement.executeQuery(sql);

		// 6.创建集合
		List<Account> list = new ArrayList<>();

        // 7.处理结果
        // 光标向下移动一行,并判断当前行是否有数据
        while(res.next()){
			// 给每行记录创建一个Account对象
			Account account = new Account();

			// 获取数据
			in id = res.getInt("id");
			String name = res.getString("name");
			double money = res.getDouble("money");

			// 赋值
			account.setId(id);
			account.setName(name);
			account.setMoney(money);

			// 存入集合
			list.add(account);
		}

        // 8.释放资源
        res.close();
        statement.close();
        connection.close();
    }
}

7、PreparedStatement

PreparedStatement作用:

  • 预编译SQl语句并执行
  • 防止SQL注入问题。

PreparedStatement优点:

  • 预编译sql,性能更高
    • 我们通过?来代替直接传入具体值,这一sql只需要编译一次sql语句。
    • 若每次都直接传入具体值,sql就每次都要编译一次,而编译sql相对执行sql是比较耗时的。
  • 防止sql注入
    • 将敏感字符进行转义

开启PreparedStatement预编译功能:在url后面加上useServerPrepStmts=true

要查看日志,需要在MySQL配置文件中配置,然后重启服务器

代码语言:javascript复制
log-output=FILE
general-log=1
gereral_log_file="D:mysql.log" #输出目录
slow-query-log=1
slow_query_log_file="D:mysql_slow.log"# 慢查询日志输出目录
long_query_time=2

PreparedStatement使用:

代码语言:javascript复制
1.获取PrepareStatement对象
// SQL语句的参数设置为?,防止SQL注入
String sql="select * from user where username=? and password=?";
// 通过Connection对象获取,并传入对应的sql语句
PrepareStatement pstmt=connection.prepareStatement(sql);

2.设置?的值
//因为姓名和密码都是String类型,所以都是getString,根据值的数据类型来选择setXxx(parameterIndex,值),parameterIndex表示给第几个值设置值。
pstmt.setString(parameterIndex,name)
pstmt.setString(parameterIndex,pwd)

3.执行SQL
// 不需要将sql作为参数传入执行
executeQuery();//查询语句时使用
executeUpdate();//更新语句时使用

PreparedStatement原理:

  1. 在获取PreparedStatement对象时,将sql语句发送给MySQL服务器进行检查,编译。
  2. 执行时就不用再进行检查,编译。
  3. 如果sql模板一样,则只需要进行一次检查、编译。

SQL注入

  • SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。

  • 简单的SQL注入代码,比如在登陆时密码框输入:'' or '1'='1'
    • 第一对’',表示截断sql查询的值,查询1=1也就是查询全表。
    • 因为我们在查询账户密码的时候通过:select * from user where username='" name "' and password='" pwd "'这样的语句来拼接字符串,导致任何类型的值都可以被拼接成功。
  • PreparedStatement解决sql注入原理:
    • 通过"select * from user where username=? and password=?"用?代替值,在设置?的值的时候会对值进行转义。
    • 比如:'' or '1' = '1',把用户非法输入的单引号进行转义,最终传入参数作为一个整体执行,从而防止 SQL 注入,而 Statement 对象不会进行此操作。

8、数据库连接池

8.1、概述

  • 数据库连接池时一个容器,赋值分配、管理数据库连接(Connection)
  • 即 将连接放入一个数据库连接池,当连接使用完后,不会立刻结束连接,而是将其放回连接池,供他人使用。
  • 如果一个连接被占用的时间超过了规定时间,则会被释放,避免程序过多时引起数据库连接遗漏。就是连接池中的连接被全部占用,后来的程序找不到连接。

好处:

  • 资源复用
  • 提升系统响应速度,因为不用重复建立连接,建立网络连接是比较耗时的
  • 避免数据库连接遗漏

8.2、数据库连接池的实现

  • 标准接口:DataSource
    • 官方(SUN)提供的数据库连接池标准接口,由第三方组织实现此接口
    • 功能:获取连接Connection getConnection()
  • 常见的数据库连接池:
    • DBCP
    • C3P0
    • Druid
  • Druid(德鲁伊)
    • Druid连接池是阿里巴巴开源的数据库连接池i项目
    • 功能强大,性能优秀,是Java最好的数据库连接池之一

8.3、Druid的使用

  1. 导入jar包到lib目录
  2. 在src下定义配置文件druid.properties
代码语言:javascript复制
driverClassName=com.mysql.jdbc.Driver
# 这里的url和JDBC连接数据库的url格式一样
url=jdbc:mysql://数据库ip
username=数据库账户
password=数据库密码
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
  1. 加载配置文件
  2. 获取数据库连接池对象
  3. 获取连接
代码语言:javascript复制
// 加载配置文件
Properties prop = new Properties();
	// 路径不确定可以通过打印System.getProperty("user.dir")查看
prop.load(new FileInputStream("druid.properties配置文件路径"));
// 获取数据库连接池对象
	// 这里可以传入不同参数创建连接池对象,使用的时候具体查看。可以先写该步骤再new相应的对象,也就是加载配置文件的步骤
DataSource dataSource = DruidDataSourceFactor.createDataSource(prop);
// 获取数据库连接connection
Connection connection = dataSource.getConnection();
System.out.println(connection);

0 人点赞