JDBC_增删改查

目录

一、JDBC概念

二、JDBC程序编写(实现对数据表的增删改)

1、JDBC程序编写步骤

2、数据表增删改

2.1. 基本步骤

2.2. 通用的增删改方法(调用即可)

2.3. 获取数据库连接(分解注释)

2.4. 使用PreparedStatement实现CRUD操作

三、JDBC程序编写(使用PreparedStatement实现查询操作)

1、通用的查询方法(调用即可)

2、ResultSet与ResultSetMetaData(结果集,元数据)

四、资源的释放(关闭)& JDBC API小结

五、升华


一、JDBC概念


JDBC(Java Database Connectivity)是一个**独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口**(一组API),定义了用来访问数据库的标准Java类库,(**java.sql,javax.sql**)使用这些类库可以以一种**标准**的方法、方便地访问数据库资源。

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

 

如果没有JDBC,那么Java程序访问数据库时是这样的:

 

有了JDBC,Java程序访问数据库时是这样的:

 

 所以,当我们使用JDBC的时候,我们会将形成一定的标准,规范化,利于形成集群化、良性化的生态

 

 引出了一种思想: ————面向接口编程

不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。                                                              

 

二、JDBC程序编写(实现对数据表的增删改)


1、JDBC程序编写步骤

 补充:

ODBC(**Open Database Connectivity**,开放式数据库连接),是微软在Windows平台下推出的。使用者在程序中只需要调用ODBC API,由 ODBC 驱动程序将调用转换成为对特定的数据库的调用请求。

 

2、数据表增删改

2.1. 基本步骤

①获取数据库连接

②获取PreparedStatement的实例 (或:预编译sql语句)

③填充占位符

④执行sql语句

⑤关闭资源

 

2.2. 通用的增删改方法(调用即可)

//通用的增、删、改操作(体现一:增、删、改 ; 体现二:针对于不同的表)
	public void update(String sql,Object ... args){
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			//1.获取数据库的连接
			conn = JDBCUtils.getConnection();
			
			//2.获取PreparedStatement的实例 (或:预编译sql语句)
			ps = conn.prepareStatement(sql);
			//3.填充占位符
			for(int i = 0;i < args.length;i++){
				ps.setObject(i + 1, args[i]);
			}
			
			//4.执行sql语句
			ps.execute();
		} catch (Exception e) {
			
			e.printStackTrace();
		}finally{
			//5.关闭资源
			JDBCUtils.closeResource(conn, ps);
			
		}
	}
//调用上述方法,实现对数据表的增删改
@Test                                                                                               public void testCommonUpdate(){                                     
String sql =”增删改语句(要有占位符)”;
调用增删改的具体方法update(sql,索引);
}

 

2.3. 获取数据库连接(分解注释)

四项基本信息要素

加载驱动的具体信息(要素一)
url(要素二)(基于什么样的协议,基于那个端口号下的数据库)
用户名user(要素三)
密码password(要素三)

要素一:Driver接口实现类
    Driver接口介绍
        java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现。
        在程序中不需要直接去访问实现了 Driver 接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现。
            - Oracle的驱动:**oracle.jdbc.driver.OracleDriver**
            - mySql的驱动: **com.mysql.jdbc.Driver**
    加载与注册JDBC驱动
        加载驱动:加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名
            **Class.forName(“com.mysql.jdbc.Driver”);**
        注册驱动:DriverManager 类是驱动程序管理器类,负责管理驱动程序
            - **使用DriverManager.registerDriver(com.mysql.jdbc.Driver)来注册驱动**
            - 通常不用显式调用 DriverManager 类的 registerDriver() 方法来注册驱动程序类的实例,因为 Driver 接口的驱动程序类**都**包含了静态代码块,在这个静态代码块中,会调用 DriverManager.registerDriver() 方法来注册自身的一个实例。下图是MySQL的Driver实现类的源码:


                

 要素二:URL
    - DBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。
    - JDBC URL的标准由三部分组成,各部分间用冒号分隔。
        - **jdbc:子协议:子名称**
        - **协议**:JDBC URL中的协议总是jdbc 
        - **子协议**:子协议用于标识一个数据库驱动程序
        - **子名称**:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了**定位数据库**提供足够的信息。包含**主机名**(对应服务端的ip地址)**,端口号,数据库名**
    举例:
        
    **几种常用数据库的 JDBC URL**
        MySQL的连接URL编写方式:
            - dbc:mysql://主机名称:mysql服务端口号/数据库名称?参数=值&参数=值
            - jdbc:mysql://localhost:3306/test
            - jdbc:mysql://localhost:3306/test**?useUnicode=true&characterEncoding=utf8**(如果JDBC程序与服务器端的字符集不一致,会导致乱码,那么可以通过参数指定服务器端的字符集)
            - jdbc:mysql://localhost:3306/test?user=root&password=123456
        Oracle 9i的连接URL编写方式:
            - jdbc:oracle:thin:@主机名称:oracle服务端口号:数据库名称
            - jdbc:oracle:thin:@localhost:1521:test
        SQLServer的连接URL编写方式:
            - jdbc:sqlserver://主机名称:sqlserver服务端口号:DatabaseName=数据库名称
            - jdbc:sqlserver://localhost:1433:DatabaseName=atguigu

 要素三、四:用户名和密码
    - user,password可以用“属性名=属性值”方式告诉数据库
    - 可以调用 DriverManager 类的 getConnection() 方法建立到数据库的连接

数据库连接方式举例

//最终版
@Test
    public  void testConnection5() throws Exception {
    	//1.加载配置文件
        InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
        Properties pros = new Properties();
        pros.load(is);
        
        //2.读取配置信息
        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        String url = pros.getProperty("url");
        String driverClass = pros.getProperty("driverClass");

        //3.加载驱动
        Class.forName(driverClass);

        //4.获取连接
        Connection conn = DriverManager.getConnection(url,user,password);
        System.out.println(conn);

    }

其中,配置文件声明在工程的src目录下:【jdbc.properties】

user=root
password=abc123
url=jdbc:mysql://localhost:3306/test
driverClass=com.mysql.jdbc.Driver

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

 

 2.4. 使用PreparedStatement实现CRUD操作

在 java.sql 包中有 3 个接口分别定义了对数据库的调用的不同方式:

- Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。 

- PrepatedStatement:SQL 语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。

- CallableStatement:用于执行 SQL 存储过程

 

通过调用 Connection 对象的 createStatement() 方法创建该对象。该对象用于执行静态的 SQL 语句,并且返回执行结果。

Statement 接口中定义了下列方法用于执行 SQL 语句:
    int excuteUpdate(String sql):执行更新操作INSERT、UPDATE、DELETE
    ResultSet executeQuery(String sql):执行查询操作SELECT 

 我们主要使用PreparedStatement,因为Statement存在弊端:

- **问题一:存在拼串操作,繁琐**

- **问题二:存在SQL注入问题**

SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令(如:SELECT user, password FROM user_table WHERE user='a' OR 1 = ' AND password = ' OR '1' = '1') ,从而利用系统的 SQL 引擎完成恶意行为的做法。

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

三、JDBC程序编写(使用PreparedStatement实现查询操作)


1、通用的查询方法(调用即可)

代码如下:

// 通用的针对于不同表的查询:返回一个对象 (version 1.0)
	public <T> T getInstance(Class<T> clazz, String sql, Object... args) {

		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			// 1.获取数据库连接
			conn = JDBCUtils.getConnection();

			// 2.预编译sql语句,得到PreparedStatement对象
			ps = conn.prepareStatement(sql);

			// 3.填充占位符
			for (int i = 0; i < args.length; i++) {
				ps.setObject(i + 1, args[i]);
			}

			// 4.执行executeQuery(),得到结果集:ResultSet
			rs = ps.executeQuery();

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

			// 6.1通过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);
					// 6.2使用反射,给对象的相应属性赋值
					Field field = clazz.getDeclaredField(columnLabel);
					field.setAccessible(true);
					field.set(t, columnVal);

				}

				return t;

			}
		} catch (Exception e) {

			e.printStackTrace();
		} finally {
			// 7.关闭资源
			JDBCUtils.closeResource(conn, ps, rs);
		}

		return null;

	}

写一个测试方法,然后调用查询方法,就可以找到我们想要的数据:

@Test
Public void testGetInstance()	{
String sql=”select id, name,email ...from 表名 where 筛选条件 (比如id=?(占位符),大于小于?(占位符)等等)”
调用查询方法getInstance(表名.class,sql,实例化占位符).var;
输出语句sout;
}

说明:使用PreparedStatement实现的查询操作可以替换Statement实现的查询操作,解决Statement拼串和SQL注入问题。

 

2、ResultSet与ResultSetMetaData(结果集,元数据)

ResultSet

- 查询需要调用PreparedStatement 的 executeQuery() 方法,查询结果是一个ResultSet 对象

- ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商提供实现

- ResultSet 返回的实际上就是一张数据表。有一个指针指向数据表的第一条记录的前面。

- ResultSet 对象维护了一个指向当前数据行的**游标**,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行。调用 next()方法检测下一行是否有效。若有效,该方法返回 true,且指针下移。相当于Iterator对象的 hasNext() 和 next() 方法的结合体。

- 当指针指向一行时, 可以通过调用 getXxx(int index) 或 getXxx(int columnName) 获取每一列的值。
      - 例如: getInt(1), getString("name")
      - **注意:Java与数据库交互涉及到的相关Java API中的索引都从1开始。**

- ResultSet 接口的常用方法:
      - boolean next()
      - getString()

 

ResultSetMetaData

- 可用于获取关于 ResultSet 对象中列的类型和属性信息的对象

- ResultSetMetaData meta = rs.getMetaData();
    - **getColumnName**(int column):获取指定列的名称
    - **getColumnLabel**(int column):获取指定列的别名
    - **getColumnCount**():返回当前 ResultSet 对象中的列数。 
    - getColumnTypeName(int column):检索指定列的数据库特定的类型名称。 
    - getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。 
    - **isNullable**(int column):指示指定列中的值是否可以为 null。 
    - isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。

问题1:得到结果集后, 如何知道该结果集中有哪些列 ? 列名是什么
     需要使用一个描述 ResultSet 的对象, 即 ResultSetMetaData

问题2:关于ResultSetMetaData
    1. **如何获取 ResultSetMetaData**: 调用 ResultSet 的 getMetaData() 方法即可
    2. **获取 ResultSet 中有多少列**:调用 ResultSetMetaData 的 getColumnCount() 方法
    3. **获取 ResultSet 每一列的列的别名是什么**:调用 ResultSetMetaData 的getColumnLabel() 方法
     

 

四、资源的释放(关闭)& JDBC API小结


资源的释放

释放ResultSet, Statement,Connection。

数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放

可以在finally中关闭,保证及时其他代码出现异常,资源也一定能被关闭。

API小结

两种思想
    面向接口编程的思想
    ORM思想(object relational mapping)
        - 一个数据表对应一个java类
        - 表中的一条记录对应java类的一个对象
        - 表中的一个字段对应java类的一个属性
    注意:sql是需要结合列名和表的属性名来写。注意起别名。

两种技术
    JDBC结果集元数据:ResultSetMetaData
        - 获取列数:getColumnCount()
        - 获取列的别名:getColumnLabel()
    通过反射,创建指定类的对象,获取指定的属性并赋值

 

五、升华


文学涵养提升法:

《清平调·其一》

[ 唐 ] 李白

云想衣裳花想容,春风拂槛露华浓。

若非群玉山头见,会向瑶台月下逢。

请问:全诗写的是谁?

再问:这个谁与李白的关系?

再再问:这个谁有什么称号?

再再再问:由这个谁你能说说唐代的一大特点是什么吗?

又双叒叕问:李白,为什么是一个剑客?号什么?

最后一问:李白是不诗王者的一员?请说出他的一句名言?近而写出能代表其豪迈特色、快意恩仇的一首诗?

最后,请把答案打在公屏上,哦不,请写在评论区。有奖竞猜......

 

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码

)">
< <上一篇
下一篇>>