二.JDBC知识点全面总结1:JDBC实战编写CRUD
1.JDBC重要接口?
①装载驱动接口
Driver接口:对接MySQL提供的Driver具体实现类 DriverManager类:封装Driver实例。
②连接
Connetion接口:获取和MySQL服务器的连接 获取connection实例的方式: driver.connect(); DriverManger.getConnection();
③执行SQL语句
Statement类(执行静态SQL语句并接受返回结果) Statement类:SQL语句无参数 PreparedStatement类继承Statement类:SQL语句有参数(防止sql注入) 执行方法 execute()运行无返回值 executeQuery()运行select语句有返回集 executeUpdate()运行Insert/delete/Update语句返回影响的行数
2.Driver和DriverManger的关系?
①对比
Driver是所有JDBC驱动类实现的接口 DriverMangement封装Driver
②使用
Driver创建驱动实例后直接获取连接 driver.connect() DriverMangement初始化(注册)Driver后直接获取连接 DriverMangement.getConnetion
③实战使用
Class.forName()加载类而且执行静态代码快。数据库驱动(Driver)中有静态代码块即注册驱动到DriverMangement 故实战可以使用DriverMangement,在加载驱动类后直接获取连接。
3.JAVA与数据库连接
①获取连接注意事项
properties的编写,注意直接连接的具体数据库 class.forName在加载驱动类时执行类中静态代码,已经从DriverMangement中注册(初始化)
②获取连接代码
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:13306/mytest?useUnicode=true&characterEncoding=utf8&useSSL=false
user=root
password=abc123
package com. likejin ;
import java. io. InputStream ;
import java. sql. Connection ;
import java. sql. DriverManager ;
import java. sql. PreparedStatement ;
import java. sql. Statement ;
import java. util. Properties ;
public class MyTest2 {
public static void main ( String [ ] args) throws Exception {
InputStream resourceAsStream = MyTest2 . class . getClassLoader ( ) . getResourceAsStream ( "jdbc.properties" ) ;
Properties properties = new Properties ( ) ;
properties. load ( resourceAsStream) ;
String driverClass = properties. getProperty ( "driverClass" ) ;
String url = properties. getProperty ( "url" ) ;
String user = properties. getProperty ( "user" ) ;
String password = properties. getProperty ( "password" ) ;
Class . forName ( driverClass) ;
Connection connection = DriverManager . getConnection ( url, user, password) ;
}
}
4.JAVA中使用statement来执行sql语句时,拼接字符串的sql注入问题?
①statement
是通过获取连接之后利用其来执行sql语句 原理:字符串拼接(由于数据必须通过’'来包含)
②sql注入问题
package com. likejin ;
import com. likejin. util. Utils ;
import java. sql. Connection ;
import java. sql. ResultSet ;
import java. sql. Statement ;
import java. util. Scanner ;
public class MyTest3 {
public static void main ( String [ ] args) throws Exception {
Connection conn = Utils . getconn ( ) ;
Statement statement = conn. createStatement ( ) ;
Scanner scanner = new Scanner ( System . in) ;
System . out. println ( "请输入ID" ) ;
String id = scanner. nextLine ( ) ;
System . out. println ( "请输入年龄" ) ;
String age = scanner. nextLine ( ) ;
String sql = "select * from student where id = '" + id + "' and age = '" + age+ "'" ;
System . out. println ( sql) ;
ResultSet resultSet = statement. executeQuery ( sql) ;
if ( resultSet. next ( ) ) {
System . out. println ( "您找的学生在这个班级" ) ;
} else {
System . out. println ( "您找的学生不在这个班级" ) ;
}
}
}
数据表 正常情况下 sql注入问题加上单引号 sql注入 不加单引号
5.使用preparedstatement进行增删改查
①preparedstatement的方法
setObject 来填充占位符 execute() 来执行增删改,返回boolean类型是否成功 executeQuery()来执行查,返回ResultSet结果集
②ResultSet的方法
next() 判断下一个是否存在,存在指正下移,返回true,不存在指正不动,返回false getObject(i) 参数为行数据的第几列,返回的是某一行数据的某一列的具体数值 getMetaData()获取到ResultSetMetaData类型,该类型有方法: getColumnCount()返回具体列数 getColumnName(i)返回某一列的名称
②注意事项
注意数据库中列从第一列开始,而JAVA数据一般从0开始,故计算时注意+1。 注意sql注入时参数也是从第一个开始的。 注意封装类时需要设置属性为public,否则无法利用反射初始化值。 注意如果要编写未知数据的查找(封装为该类的list),需要知道数据的类型: 可以用泛型方法来传入封装的数据类型 Class <T> clazz T t
②代码
package com. likejin. util ;
import com. likejin. MyTest2 ;
import com. likejin. Student ;
import java. io. InputStream ;
import java. lang. reflect. Field ;
import java. sql. * ;
import java. util. ArrayList ;
import java. util. List ;
import java. util. Properties ;
public class Utils {
public static Connection getconn ( ) throws Exception {
InputStream resourceAsStream = MyTest2 . class . getClassLoader ( ) . getResourceAsStream ( "jdbc.properties" ) ;
Properties properties = new Properties ( ) ;
properties. load ( resourceAsStream) ;
String driverClass = properties. getProperty ( "driverClass" ) ;
String url = properties. getProperty ( "url" ) ;
String user = properties. getProperty ( "user" ) ;
String password = properties. getProperty ( "password" ) ;
Class . forName ( driverClass) ;
Connection connection = DriverManager . getConnection ( url, user, password) ;
return connection;
}
public static boolean updateData ( String sql, Object . . . args) throws Exception {
Connection conn = getconn ( ) ;
PreparedStatement preparedStatement = conn. prepareStatement ( sql) ;
for ( int i = 0 ; i < args. length; i++ ) {
preparedStatement. setObject ( i + 1 , args[ i] ) ;
}
boolean execute = preparedStatement. execute ( ) ;
preparedStatement. close ( ) ;
conn. close ( ) ;
return execute;
}
public static List selectData ( String sql, Object . . . args) throws Exception {
Connection conn = getconn ( ) ;
PreparedStatement preparedStatement = conn. prepareStatement ( sql) ;
for ( int i = 0 ; i < args. length; i++ ) {
preparedStatement. setObject ( i + 1 , args[ i] ) ;
}
ResultSet resultSet = preparedStatement. executeQuery ( ) ;
ArrayList < Student > students = new ArrayList < > ( ) ;
int i = 0 ;
while ( resultSet. next ( ) ) {
Student student = new Student ( ) ;
student. setId ( resultSet. getInt ( 1 ) ) ;
student. setAge ( resultSet. getInt ( 2 ) ) ;
student. setGrade ( resultSet. getInt ( 3 ) ) ;
i = i + 1 ;
students. add ( student) ;
}
return students;
}
public static < T > List < T > selectData ( Class < T > clazz, String sql, Object . . . args) throws Exception {
Connection conn = getconn ( ) ;
PreparedStatement preparedStatement = conn. prepareStatement ( sql) ;
for ( int i = 0 ; i < args. length; i++ ) {
preparedStatement. setObject ( i + 1 , args[ i] ) ;
}
ArrayList < T > ts = new ArrayList < > ( ) ;
ResultSet resultSet = preparedStatement. executeQuery ( ) ;
ResultSetMetaData metaData = resultSet. getMetaData ( ) ;
int columnCount = metaData. getColumnCount ( ) ;
while ( resultSet. next ( ) ) {
T t = clazz. newInstance ( ) ;
for ( int i = 0 ; i< columnCount; i++ ) {
Field dd = clazz. getDeclaredField ( metaData. getColumnName ( i+ 1 ) ) ;
dd. set ( t, resultSet. getObject ( i+ 1 ) ) ;
}
ts. add ( t) ;
}
return ts;
}
}
6.自定义通用查询方法
①缺点
运行时类和类类型不同,无法在方法中就强转为需要的类类型。 stuent.getClass() 或者Student.class都和 Student不同 故如果想获得类类型,就需要运用泛型。 举例说明 如果想在传入方法中获取该类的类型如何获取? 利用泛型 T t或者 Class<T> clazz都可获取类型为T 利用Object o 获取不到类类型,最多获取运行时类的实例,故需要在获取方法的返回值后手动进行强转。 对象获取到类类型的数据是什么?为什么不能强转? 即最多获取到类类型字符串 String typeName = o1.getClass().getTypeName();由于编译的限制,无法去利用字符串强转对象。
②代码
public static List selectData5 ( Object o, String sql, Object . . . args) throws Exception {
InputStream resourceAsStream = Utils . class . getClassLoader ( ) . getResourceAsStream ( "jdbc.properties" ) ;
Properties properties = new Properties ( ) ;
properties. load ( resourceAsStream) ;
final String url = properties. getProperty ( "url" ) ;
String user = properties. getProperty ( "user" ) ;
String password = properties. getProperty ( "password" ) ;
Class . forName ( properties. getProperty ( "driverClass" ) ) ;
Connection connection = DriverManager . getConnection ( url, user, password) ;
PreparedStatement preparedStatement = connection. prepareStatement ( sql) ;
for ( int i = 0 ; i< args. length; i++ ) {
preparedStatement. setObject ( i+ 1 , args[ i] ) ;
}
ResultSet resultSet = preparedStatement. executeQuery ( ) ;
ResultSetMetaData metaData = resultSet. getMetaData ( ) ;
ArrayList arrayList = new ArrayList ( ) ;
int columnCount = metaData. getColumnCount ( ) ;
while ( resultSet. next ( ) ) {
Object o1 = o. getClass ( ) . newInstance ( ) ;
for ( int i = 0 ; i< columnCount; i++ ) {
String columnName = metaData. getColumnName ( i + 1 ) ;
Field field = o1. getClass ( ) . getField ( columnName) ;
field. set ( o1, resultSet. getObject ( i+ 1 ) ) ;
}
arrayList. add ( o1) ;
}
return arrayList;
}
public static void main ( String [ ] args) throws Exception {
String sql = "select * from student where id<?" ;
List students1 = null ;
List list = selectData5 ( new Student ( ) , sql, 10 ) ;
Iterator iterator = list. iterator ( ) ;
while ( iterator. hasNext ( ) ) {
System . out. println ( ( Student ) iterator. next ( ) ) ;
}
}
未更新