菜鸟学JAVA之——JDBC编程

JDBC基本知识

一、引入

Java想要连接到MySQL上,就需要MySQL提供的连接用的jar包,这个jar包就是JDBC

  • SPI(Service Provider Interface)过程:是Java提供的一种接口创建与表达形式。

  • Java负责提供一套统一的数据库连接过程和方法。

    比如Java操作MySQL连接去查询数据库的时候,调用的方法是find,但是Java操作Sybase数据库查询的时候,调用的是query方法。

    客户A使用的是MySQL数据库,客户B使用的是Sybase数据库,两人要想换库就很麻烦

  • Java提供统一接口以后,为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。

  • JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。

以上就是SPI的过程,Java提供接口,厂商负责伴随产品一起发布。

JDBC连接数据库使用的过程

贾琏欲执释:

  • 加载驱动
  • 获取数据库连接
  • 预编译SQL语句
  • 执行SQL语句得到结果
  • 释放资源

二、获取数据库连接

要素一:加载驱动Driver、接口实现类

  • 加载驱动:加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名

    • Class.forName(“com.mysql.cj.jdbc.Driver”);
  • java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现。

  • 在程序中不需要直接去访问实现了 Driver 接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现。

要素二:URL

  • JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。

  • MySQL的连接URL编写方式:jdbc:mysql://主机名称:mysql服务端口号/数据库名称?参数=值&参数=值

要素三:用户名和密码

  • user,password可以用“属性名=属性值”方式告诉数据库
  • 可以调用 DriverManager 类的 getConnection() 方法建立到数据库的连接

加载驱动与获取连接的方式:

public class Main {
    
    
    public static void main(String[] args) {
    
    
        //加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //获取连接
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db_test?serverTimezone=UTC","root","123456");
    }
}

以上这种方式其实是有弊端的,在开发过程中,这种参数信息一般都不会直接写在代码中,而是写在配置文件中。

说明:使用配置文件的方式保存配置信息,在代码中加载配置文件

使用配置文件的好处:

①实现了代码和数据的分离,如果需要修改配置信息,直接在配置文件中修改,不需要深入代码(实现了解耦)
②如果修改了配置信息,省去重新编译(打包)的过程。

配置文件中的四个最基本要素:数据库厂商、要连接哪个数据库、用户名、密码

三、使用PreparedStatement实现CRUD操作

  • 在 java.sql 包中定义了对数据库的调用的不同方式:
    • Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。
    • PrepatedStatement:SQL 语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。

1、使用Statement操作数据表存在弊端

  • 问题一:存在拼串操作,繁琐
  • 问题二:存在SQL注入问题

SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令 ,从而利用系统的 SQL 引擎完成恶意行为的做法。

对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(从Statement扩展而来) 取代 Statement 就可以了。

代码演示

public class Main {
    
    
    public static void main(String[] args) throws Exception {
    
    
        //加载数据库连接
        Class.forName("com.mysql.cj.jdbc.Driver");//要是更换数据库只需要更改参数即可
        //连接数据库
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db_test?serverTimezone = UTC","root","123456");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        String pwd = scanner.nextLine();
        String sql = "select * from tb_user where name = '" + name + "' and password = '" + pwd + "'";
        System.out.println(sql);
        Statement st = connection.createStatement();
        ResultSet rt = st.executeQuery(sql);
        while(rt.next()) {
    
    
            System.out.print(rt.getString(1) + "\t");
            System.out.print(rt.getString(2) + "\t");
            System.out.println(rt.getString(3));
        }
    }
}

比如:你在控制台输入’ union select * from tb_user where 1 = '1,执行的SQL语句则为select * from tb_user where name = ‘dsaf’ and password = ‘’ union select * from tb_user where 1 = ‘1’,这样会造成所有人的信息泄露

2、PreparedStatement介绍

  • 可以通过调用 Connection 对象的 preparedStatement(String sql) 方法获取 PreparedStatement 对象
  • PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句
  • PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值

3、使用PreparedStatement实现增删改操作

首先将数据库连接过程简单封装起来以便后续使用

public class JDBCUtils {
    
    
    public static Connection getConnection() throws Exception {
    
    
        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db_test?serverTimezone=UTC","root","123456");
    }
}
public void update(String sql, Object...args) {
    
    
    Connection conn = null;
    PreparedStatement ps = null;
    try {
    
    
        conn = JDBCUtils.getConnection();
		ps = conn.prepareStatement(sql);
        for(int i = 0;i < args.length;i++){
    
    
			ps.setObject(i + 1, args[i]);
		}
        ps.executeUpdate();
		}finally{
    
    
			//关闭资源
			//略
		}
}

4、使用PreparedStatement实现查询操作

public <T> T getInstance(Class<T> clazz, String sql, Object... args) {
    
    //泛型方法
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
    
    
			conn = JDBCUtils.getConnection();
			ps = conn.prepareStatement(sql);
			for (int i = 0; i < args.length; i++) {
    
    
				ps.setObject(i + 1, args[i]);
			}
			rs = ps.executeQuery();

			// 得到结果集的元数据:ResultSetMetaData
			ResultSetMetaData rsmd = rs.getMetaData();

			// 通过ResultSetMetaData得到columnCount,columnLabel;通过ResultSet得到列值
			int columnCount = rsmd.getColumnCount();
			if (rs.next()) {
    
    
				T t = clazz.newInstance();//查到了信息才创建对象
				for (int i = 0; i < columnCount; i++) {
    
    // 遍历每一个列
					// 获取列值
					Object columnVal = rs.getObject(i + 1);
					// 获取列的别名:列的别名,使用类的属性名充当
					String columnLabel = rsmd.getColumnLabel(i + 1);
                    
					// 使用反射,给对象的相应属性赋值
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnVal);         
				}
				return t;
			}
		} catch (Exception e) {
    
    
			e.printStackTrace();
		} finally {
    
    
			// 关闭资源
			//略
		}
		return null;
	}

5、ResultSet

  • 查询结果是一个ResultSet 对象,他返回的实际上是一个数据表。有一个指针指向数据表的第一条记录的前面( next() ),调用 next()方法检测下一行是否有效。若有效,该方法返回 true,且指针下移。相当于Iterator对象的 hasNext() 和 next() 方法的结合体。
  • 当指针指向一行时, 可以通过调用 getXxx(int index) 或 getXxx(int columnName) 获取每一列的值。
    • 例如: getInt(1), getString(“name”)
    • 注意:Java与数据库交互涉及到的相关Java API中的索引都从1开始。

6、ResultSetMetaData

  • 可用于获取关于 ResultSet 对象中列的类型和属性信息的对象
  • 调用 ResultSet 的 getMetaData() 方法即可获得ResultSetMetaData
  • 他的两个主要方法
    • getColumnLabel(int column):获取指定列的别名,如果没有别名则返回字段名
    • getColumnCount():返回当前 ResultSet 对象中的列数。

四、批量插入

JDBC的批量处理语句包括下面三个方法:

  • addBatch(String):添加需要批量处理的SQL语句或是参数;
  • executeBatch():执行批量处理语句;
  • clearBatch():清空缓存的数据

代码实现

public void testInsert() throws Exception{
    
    
	Connection conn = JDBCUtils.getConnection();
		
	//1.设置为不自动提交数据
	conn.setAutoCommit(false);
		
	String sql = "insert into goods(name)values(?)";
	PreparedStatement ps = conn.prepareStatement(sql);
		
	for(int i = 1;i <= 1000000;i++){
    
    
		ps.setString(1, "name_" + i);
			
		//1.“攒”sql
		ps.addBatch();
			
		if(i % 500 == 0){
    
    
			//2.执行
			ps.executeBatch();
			//3.清空
			ps.clearBatch();
		}
	}
		
	//2.提交数据
	conn.commit();
    
	JDBCUtils.closeResource(conn, ps);
}

猜你喜欢

转载自blog.csdn.net/ysf15609260848/article/details/105052712