JDBC

Posted 半颗桃核

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDBC相关的知识,希望对你有一定的参考价值。

jdbc

1、概念:

Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标。我们通常说的JDBC是面向关系型数据库的

即Java语言操作数据库。

技术图片

2、入门步骤:

前提导入驱动jar包技术图片

1、注册驱动

2、获取数据库连接对象 Connection

3定义sql

4、获取执行sql的语句对象 Statement

5、执行sql语句,接受返回结果

6、处理结果

7、释放资源

public class JdbcDemo {
  public static void main(String[] args) {
      try {
          //1、注册驱动
          Class.forName("com.mysql.jdbc.Driver");
          //2获取数据库连接对象
          Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db2", "root", "root");
          //3定义sql语句
          String sql = "update stu set name = ‘li‘ 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();
      } catch (Exception e) {
          e.printStackTrace();
      }
  }
}

3、详解各个对象

a、DriverManager--驱动管理对象

功能:

1注册驱动

static void registerDriver(Driver driver) 注册与给定的驱动程序 DriverManager 。

写代码使用:Class.forName("com.mysql.jdbc.Driver");

通过查看源代码发现:在com.mysql.jdbc.Driver类中存在静态代码块

try
{
DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can‘t register driver!");
}

}

2获取数据库连接

方法:static Connection getConnection(String url, String user, String password )

参数

url - 形式为 jdbc:subprotocol:subname的数据库网址

语法:jdbc:mysql://ip地址(域名):端口号/数据库名称

例子:jdbc:mysql://127.0.0.1:3306/db2

user - 正在连接的数据库用户 ? password - 用户密码

b、Connection--数据库连接对象

1获取执行sql的对象

Statement createStatement() 创建一个 Statement对象,用于将SQL语句发送到数据库。

PreparedStatement prepareStatement(String sql) 创建一个 PreparedStatement对象,用于将参数化的SQL语句发送到数据库。

2、管理事务:

开启事务:setAutoCommit(boolean autoCommit) --调用该方法设置参数为false,即开启事务。

提交事务:commit()

回滚事务:rollback()

c、Statement--执行sql的对象

1执行sql

1oolean execute(String sql) :可以执行任意的sql 了解

2、int executeUpdate(String sql) :可以执行DML(insertupdatedelete)语句、DDL(createalterdrop)语句

返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则成功,反之,则失败。

3、ResultSet executeQuery(String sql) :执行DQL(select)语句

d、ResultSet--结果集对象

1、next() 游标向下移动一行

2、getxxx(参数):获取数据

xxx:代表数据类型 如:int getInt(),String getString()

1、int --代表列的编号,从1开始 如:getString(1)

while (rs.next()){
  System.out.println(rs.getInt(1)+","+rs.getString(2)+","+rs.getString(3));
}

2、String--代表列名。如:getString("name")

while (rs.next()){    System.out.println(rs.getInt("id")+rs.getString("name")+rs.getString("phone_num"));
public class JdbcDemo01 {
  public static void main(String[] args) {
      Connection connection = null;
      Statement statement = null;
      try {
          //注册驱动
          Class.forName("com.mysql.jdbc.Driver");
          //获取数据库连接对象
          connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db2", "root", "root");
          //定义sql语句
          String sql = "select * from person";
          //获取执行sql的statement对象
          statement = connection.createStatement();
          //执行sql语句
          ResultSet rs = statement.executeQuery(sql);
          //处理结果集
          while (rs.next()){
              Person person = new Person();
              person.setId(rs.getInt("id"));
              person.setName(rs.getString("name"));
              person.setAge(rs.getInt("age"));
              System.out.println(person);
          }
      } catch (ClassNotFoundException e) {
          e.printStackTrace();
      }catch (SQLException e){
          e.printStackTrace();
      }
  }
}

Jdbc工具类——练习

public class JdbcUtils {
  private static String url;
  private static String user;
  private static String password;
  private static String driver;
  static {
      //1、创建properties集合类
      Properties properties = new Properties();
      try {
          //2、加载文件
          //获取src路径下的文件的方式--ClassLoader 类加载器
          ClassLoader classLoader = JdbcUtils.class.getClassLoader();
?
//           InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc.properties");//返回用于读取指定资源的输入流。
//           properties.load(resourceAsStream);
?
          URL resourceUrl = classLoader.getResource("jdbc.properties");
          String urlPath = resourceUrl.getPath();
          System.out.println(urlPath);
          properties.load(new FileReader(urlPath));
          //3、获取配置的数据,赋值
          JdbcUtils.url = properties.getProperty("url");
          user = properties.getProperty("user");
          password = properties.getProperty("password");
          driver = properties.getProperty("driver");
          //4、加载驱动
          Class.forName(driver);
      } catch (IOException e) {
          e.printStackTrace();
      } catch (ClassNotFoundException e) {
          e.printStackTrace();
      }
  }
  /***
  * @Author 俺家笨丫头
  * @Description: 获取数据库连接
  * @Date: 2020/5/15 23:52
  * @Param []
  * @throws Exception
  * @return java.sql.Connection
  */
  public static Connection getConnection() throws SQLException {
      return DriverManager.getConnection(url,user,password);
  }
  /**
  * @Author 俺家笨丫头
  * @Description: 释放资源
  * @Date: 2020/5/15 23:52
  * @Param [statement, connection]
  * @throws Exception
  * @return void
  */
  public static void close(Statement statement, Connection connection){
      if (statement != null){
          try {
              statement.close();
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
      if (connection != null){
          try {
              connection.close();
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
  }
  public static void close(ResultSet rs, Statement statement, Connection connection){
      if (rs != null){
          try {
              rs.close();
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
      if (statement != null){
          try {
              statement.close();
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
      if (connection != null){
          try {
              connection.close();
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
  }
}
public class JdbcDemo02 {
  public static void main(String[] args) {
      List<Person> personList = findAll();
      System.out.println(personList);
      System.out.println(personList.size());
  }
?
  private static List<Person> findAll() {
      ArrayList<Person> list = new ArrayList<>();
      String sql = "select * from person";
      Connection connection = null;
      try {
          connection = JdbcUtils.getConnection();
          Statement statement = connection.createStatement();
          ResultSet rs = statement.executeQuery(sql);
          while (rs.next()){
              Person person = new Person();
              person.setId(rs.getInt("id"));
              person.setName(rs.getString("name"));
              person.setAge(rs.getInt("age"));
              list.add(person);
          }
      } catch (SQLException e) {
          e.printStackTrace();
      }
      return list;
  }
}

登录小练习(有bug)sql注入问题

public class Demo03 {
  public static void main(String[] args) {
      Scanner scanner = new Scanner(System.in);
      System.out.println("请输入用户名字:");
      String name = scanner.next();
      System.out.println("请输入密码:");
      String password = scanner.next();
      boolean b = logIn(name, password);
      if(b){
          System.out.println("登录成功");
      }else{
          System.out.println("用户名或密码错误");
      }
  }
?
  private static boolean logIn(String name, String password) {
      Connection connection = null;
      Statement statement = null;
      ResultSet rs = null;
      if (name == null || password == null){
          return false;
      }
      String sql = "select * from users where name = ‘" +name+
              "‘ and password = ‘" + password +
              "‘";
      System.out.println("sql:" + sql);
      try {
          connection = JdbcUtils.getConnection();
          connection.setAutoCommit(true);
          statement = connection.createStatement();
          rs = statement.executeQuery(sql);
          return rs.next();
      } catch (SQLException e) {
          e.printStackTrace();
      }finally {
          JdbcUtils.close(rs,statement,connection);
      }
      return false;
  }
}

e、PreparedStatement--执行sql的对象

  • 表示预编译的SQL语句的对象。

    SQL语句已预编译并存储在PreparedStatement对象中。 然后可以使用该对象多次有效地执行此语句。

    1、SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题

    1、用户随便输入密码:a‘ or ‘a‘ = ‘a‘

    2、sql:select * from users where name = ‘huhu‘ and password = ‘a‘ or ‘a‘ = ‘a‘

    2、解决sql注入问题:使用PreparedStatement对象来解决

    3、预编译的sql:参数使用?作为占位符

    4、步骤:

    1、导入驱动架包mysql-connector-java-5.1.40-bin.jar

    2、注册驱动

    3、获取数据库连接对象

    4、定义sql

    注意sql的参数使用?作为占位符。如 :select * from users where name = ? and password = ?;

    5、获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)

    6、给?赋值

    方法:setXXX(参数1,参数2)

    参数1--?的位置编号 从1开始

    参数2--?的值

    7、执行sql,接受返回结果

    8、处理结果

    9、释放资源

public class Demo04 {
  public static void main(String[] args) {
      Scanner scanner = new Scanner(System.in);
      System.out.println("请输入用户名字:");
      String name = scanner.next();
      System.out.println("请输入密码:");
      String password = scanner.next();
      boolean b = logIn(name, password);
      if(b){
          System.out.println("登录成功");
      }else{
          System.out.println("用户名或密码错误");
      }
  }
?
  private static boolean logIn(String name, String password) {
      Connection connection = null;
      PreparedStatement preparedStatement = null;
      ResultSet rs = null;
      if (name == null || password == null){
          return false;
      }
      try {
          connection = JdbcUtils.getConnection();
          connection.setAutoCommit(true);
          String sql = "select * from users where name = ? and password = ?";
          preparedStatement = connection.prepareStatement(sql);
          preparedStatement.setString(1,name);
          preparedStatement.setString(2,password);
          rs = preparedStatement.executeQuery();
          return rs.next();
      } catch (SQLException e) {
          e.printStackTrace();
      }finally {
          JdbcUtils.close(rs,preparedStatement,connection);
      }
      return false;
  }
}

4、JDBC控制事务:

1、事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。

2、操作:开启事务、提交事务、回滚事务。

3、使用connection对象来管理事务

开启事务:setAutoCommit(boolean autoCommit) --调用该方法设置参数为false,即开启事务。

提交事务:commit()

回滚事务:rollback()

默认的话为自动提交, 每执行一个update ,delete或者insert的时候都会自动提交到数据库,无法回滚事务。 设置connection.setautocommit(false);只有程序调用connection.commit()的时候才会将先前执行的语句一起提交到数据库,这样就实现了数据库的事务。

true:sql命令的提交(commit)由驱动程序负责 false:sql命令的提交由应用程序负责,程序必须调用commit或者rollback方法

public class Demo05 {
  public static void main(String[] args) {
      Connection connection = null;
      PreparedStatement preparedStatement = null;
      PreparedStatement preparedStatement2 = null;
?
      try {
          //获取数据库连接
          connection = JdbcUtils.getConnection();
          //开启事务
          connection.setAutoCommit(false);
          //sql语句
          String sql1 = "update person a set a.age = a.age - ? where a.id = ?";
          String sql2 = "update person a set a.age = a.age + ? where a.id = ?";
          //获取执行sql的对象
          preparedStatement = connection.prepareStatement(sql1);
          preparedStatement2 = connection.prepareStatement(sql1);
          //设置参数
          preparedStatement.setInt(1,5);
          preparedStatement.setInt(2,1);
?
          preparedStatement2.setInt(1,5);
          preparedStatement2.setInt(2,5);
          //执行sql
          preparedStatement.executeUpdate();
          int i = 3/0;//制造异常
          preparedStatement2.executeUpdate();
          //提交事务
          connection.commit();
      } catch (Exception e) {
          if (connection != null){
              try {
                  connection.rollback();//回滚事务
              } catch (SQLException e1) {
                  e1.printStackTrace();
              }
          }
          e.printStackTrace();
      }finally {
          JdbcUtils.close(preparedStatement,connection);
          JdbcUtils.close(preparedStatement2,connection);
      }
  }
}

5、数据库连接池

A、概念:其实就是一个容器(集合),存放数据库连接的容器。

当系统初始化好之后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从 容器中获取连接对象,用户访问完后,会将连接对象归还给容器。

B、优点:1、节约资源 2、用户访问高效

C、实现

1、标准接口:DataSource javax.sql包下

方法:

a、获取连接:getConnection()

b、归还连接:如果连接对象Connection是从连接池中获取的,那么调用connection.close()方法,则不会再关闭连接了。而是归还链接。

2、一般我们不去实现它,由数据库厂商来实现

1、C3P0:数据库连接池技术

2、Druid:数据库连接池实现技术,有阿里巴巴提供的

D、C3P0数据库连接池技术

步骤:

1、导入jar包:c3p0-0.9.5.5.jar mchange-commons-java-0.2.19.jar 和数据库的驱动架包

2、定义配置文件:

名称:c3p0.properties.xml 或者 c3p0-config.xml

路径:直接将配置文件放在src目录下即可

3、创建核心对象 数据库连接池对象 ComboPooledDataSource

4、获取连接:getConnection

c3p0-config.xml的配置

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
    <!-- 连接参数 -->
    <!-- 数据库驱动名 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <!-- 数据库的url -->
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/db2</property>
    <property name="user">root</property>
    <property name="password">root</property>
     
    <!-- 连接池参数 -->
    <!--初始化时申请获取5个连接,取值应在minPoolSize与maxPoolSize之间。-->
    <property name="initialPoolSize">5</property>
    <!-- 连接池里允许申请的最大的连接数量 -->
    <property name="maxPoolSize">10</property>
    <!-- 最小的连接数量 -->
    <property name="minPoolSize">4</property>
    <!--超时时间 (等待3秒才会报错)-->
      <property name="checkoutTimeout">3000</property>
  </default-config>
 
  <named-config name="c3p0mysql">
    <!-- 连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/db2</property>
    <property name="user">root</property>
    <property name="password">root</property>
    <!-- 连接池参数 -->
    <property name="initialPoolSize">4</property>
    <property name="maxPoolSize">8</property>
    <!-- 最小的连接数量 -->
    <property name="minPoolSize">3</property>
    <!--超时时间-->
      <property name="checkoutTimeout">1000</property>
  </named-config>
 
  <named-config name="c3p0oracle">
    <property name="driverClass">oracle.jdbc.driver.OracleDriver</property>
    <property name="jdbcUrl">jdbc:oracle:thin:@地址:端口:ORCL</property>
    <property name="user">root</property>
    <property name="password">root</property>
    <!--初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。-->
    <property name="initialPoolSize">3</property>
    <!--连接池中保留的最大连接数。-->
    <property name="maxPoolSize">6</property>
    <!--连接池中保留的最小连接数 -->
    <property name="minPoolSize">2</property>
    <!--超时时间-->
      <property name="checkoutTimeout">1000</property>
  </named-config>
</c3p0-config>
public class C3p0Demo01 {
  public static void main(String[] args) {
      //1创建数据库连接池对象
      //DataSource dataSource = new ComboPooledDataSource();//默认<default-config>
      DataSource dataSource = new ComboPooledDataSource("c3p0mysql");//使用指定的配置
      //2获取连接对象
      try {
          Connection connection = dataSource.getConnection();
?
          //3打印
          System.out.println(connection);
      } catch (SQLException e) {
          e.printStackTrace();
      }
  }
}
public class C3p0Demo02 {
  public static void main(String[] args) throws SQLException {
      //1创建数据库连接对象
      DataSource dataSource = new ComboPooledDataSource();//使用默认<default-config>
      //2获取连接
      for (int i = 1; i <= 11; i++) {
          Connection connection = dataSource.getConnection();
          System.out.println(i+":"+connection);
?
          if (i==5){
              connection.close();//归还连接到连接池
          }
      }
  }
}

E、Druid:数据库连接池实现技术,有阿里巴巴提供的

1步骤:

1、导入jar包:druid-1.1.21.jar 和数据库的驱动架包

2、定义配置文件:

是properties形式的

可以是任意名称,可以放在任意目录下

3、创建核心对象 数据库连接池对象 DruidDataSourceFactory

4、获取连接:getConnection

2定义工具类

1定义一个JDBCUtils

2提供静态代码块加载配置文件,初始化连接池对象

3提供方法

1获取连接方法:通过数据库连接池获取连接

2释放资源

3获取连接池的方法

JDBCUtils工具类

public class JdbcUtils {
  //1定义成员变量
  private static DataSource dataSource;
  static {
      InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
      try {
          Properties properties = new Properties();
          properties.load(inputStream);
          dataSource = DruidDataSourceFactory.createDataSource(properties);
      } catch (IOException e) {
          e.printStackTrace();
      } catch (Exception e) {
          e.printStackTrace();
      }
  }
  public static Connection getConnetion() throws SQLException {
      return dataSource.getConnection();
  }
  public static void close(Statement statement,Connection connection){
      if (statement != null){
          try {
              statement.close();
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
      if (connection !=null){
          try {
              connection.close();
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
  }
?
  public static void close(ResultSet resultSet, Statement statement, Connection connection){
      if (resultSet != null){
          try {
              resultSet.close();
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
      if (statement != null){
          try {
              statement.close();
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
      if (connection !=null){
          try {
              connection.close();
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
  }
?
  public static DataSource getDataSource(){
      return dataSource;
  }
}

druid.properties文件的配置

# druid.properties文件的配置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/db2
username=root
password=root
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大超时时间
maxWait=3000

小练习

public class DruidDemo02 {
  public static void main(String[] args) {
      Connection connetion = null;
      PreparedStatement statement = null;
      try {
          connetion = JdbcUtils.getConnetion();
          connetion.setAutoCommit(false);
          String sql = "insert into person values(null,?,?)";
          statement = connetion.prepareStatement(sql);
          statement.setString(1,"李毅");
          statement.setInt(2,26);
          int count = statement.executeUpdate();
          System.out.println(count);
          connetion.commit();
          connetion.close();
      } catch (SQLException e) {
          try {
              connetion.rollback();
          } catch (SQLException e1) {
              e1.printStackTrace();
          }
          e.printStackTrace();
      }finally {
          JdbcUtils.close(statement,connetion);
      }
?
  }
}

6、Spring JDBC

Spring 框架对jdbc的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发

步骤:

1、导入架包

2、创建JDBCTemplate对象。依赖于数据源DataSource

JdbcTemplate template = new JdbcTemplate(ds);

3、调用JdbcTemplate的方法来完成CRUD的操作

update():执行DML语句。增删改语句。

queryForMap():查询结果将结果集封装为map集合 //注意这个方法的查询结果集长度只能是1

queryForList():查询结果将结果集封装为list集合

query():查询结果,将结果封装为JavaBean对象//查询返回对象类型的集合

new BeanPropertyRowMapper<类型>(类型.class)

queryForObject():查询结果,将结果封装为对象//一般用来查询聚合函数的

public class JdbcTemplateDemo01 {
  public static void main(String[] args) {
      //1导jar包
      //2创建JdbcTemplate对象
      JdbcTemplate template = new JdbcTemplate(JdbcUtils.getDataSource());
      //3调用方法
      String sql = "insert into person values(?,?,?)";
      int count = template.update(sql, null, "千年老妖", 1000);
      System.out.println(count);
  }
}

技术图片

public class JdbcTemplateDemo02 {
  private JdbcTemplate template = new JdbcTemplate(JdbcUtils.getDataSource());
  @Test
  public void test1(){
      Person person = new Person();
      ArrayList<Person> list = new ArrayList<>();
      String sql = "update person set age = ? where id = ?";
      int update = template.update(sql, 26, 1);
      System.out.println(update);
  }
  @Test
  public void test2(){
      String sql = "insert into person values (?,?,?)";
      int update = template.update(sql, null,"刘飞",28);
      System.out.println(update);
  }
  @Test
  public void test3(){
      String sql = "delete from person where id = ?";
      int update = template.update(sql,4);
      System.out.println(update);
  }
  @Test
  public void test4(){
      String sql = "select * from person where id = ?";
      //注意这个方法的查询结果集长度只能是1
      Map<String, Object> stringObjectMap = template.queryForMap(sql, 1);
      Set<Map.Entry<String, Object>> entrySet = stringObjectMap.entrySet();
      /*for (Map.Entry<String, Object> entry : entrySet) {
          System.out.println(entry.getKey()+entry.getValue());
      }*/
      Iterator<Map.Entry<String, Object>> iterator = entrySet.iterator();
      while (iterator.hasNext()){
          Map.Entry<String, Object> entry = iterator.next();
          System.out.println(entry.getKey()+entry.getValue());
      }
  }
  @Test
  public void test5(){
      String sql = "select * from person where id = ? or id = ?";
      List<Map<String, Object>> maps = template.queryForList(sql,1,2);
      //System.out.println(maps);
      for (Map<String, Object> map : maps) {
          System.out.println(map);
      }
  }
?
  @Test
  public void test6(){
      String sql = "select * from person where id = ? or id = ?";
?
      /*List<Person> list = template.query(sql, new RowMapper<Person>() {
          @Override
          public Person mapRow(ResultSet resultSet, int i) throws SQLException {
              int id = resultSet.getInt("id");
              String name = resultSet.getString("name");
              int age = resultSet.getInt("age");
              Person person = new Person(id,name,age);
              return person;
          }
      },1,3);
      for (Person person : list) {
          System.out.println(person);
      }*/
?
      List<Person> list = template.query(sql, new BeanPropertyRowMapper<Person>(Person.class), 1, 3);
      System.out.println(list);
  }
  @Test
  public void test7(){
      String sql = "select count(1) from person where id = ? or id = ?";
      Integer integer = template.queryForObject(sql, Integer.class,1,5);
      System.out.println(integer);
  }
}

 

以上是关于JDBC的主要内容,如果未能解决你的问题,请参考以下文章

面试常用的代码片段

mysql jdbc源码分析片段 和 Tomcat's JDBC Pool

JDBC操作数据库之查询数据

如何在片段中填充列表视图?

在 myeclipse中进行连接sql server的测试

MYBATIS05_ifwherechoosewhentrimsetforEach标签sql片段