问题总结
1. 获取连接的时候
java.sql.SQLException: java.lang.VerifyError: (class: com/mysql/jdbc/DatabaseMetaData, method: supportsRefCursors signature: ()Z) Illegal use of nonvirtual function call
JDBC:
java操作数据库.jdbc是oracle公司指定的一套规范(一套接口)
驱动:jdbc的实现类.由数据库厂商提供.
我们就可以通过一套规范操作不同的数据库了(多态)
jdbc作用:
连接数据库 Connection
发送sql语句 Statement处理结果 ResultSet
使用
步骤
准备
数据库和表,,,,,,创建一个项目,,,,,,导入驱动jar包
编码
注册驱动
获取连接
编写sql
创建预编译的语句执行者
设置参数
执行sql
处理结果
释放资源
驱动注册问题
try {
// 注册驱动,注册两次 : com.mysql.jdbc.Driver的静态代码块里调用相同注册方法
java.sql.DriverManager.registerDriver(new com.mysql.jdbc.Driver());
} catch (SQLException e) {
e.printStackTrace();
}
加载将类加载到内存中即可:
Class.forName("com.mysql.jdbc.Driver");// 包名+类名
Class clazzClass = com.mysql.jdbc.Driver.class;
Class clazzClass2 = (new com.mysql.jdbc.Driver()).getClass();
配置文件
static {
try {
// 读取配置文件
InputStream is = JdbcUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
// InputStream is = JdbcUtil.class.getResourceAsStream("jdbc.properties");
Properties prop = new Properties();
prop.load(is);
// jdbc:mysql://localhost:3306/school
url = prop.getProperty("url");
username = prop.getProperty("username");
password = prop.getProperty("password");
// com.mysql.jdbc.Driver
String driverClass = prop.getProperty("driverClass");
Class.forName(driverClass);
} catch (Exception e) {
// 只能抓取
throw new ExceptionInInitializerError(e);
}
}
SQL注入问题(statement)
/** 第三步:语句执行者 **/
String username = "aaaa";
String pwd = "bb or 1=1 or 1='1";// 恒成立
String sql = "select * from tb_student where username='" + username + "' and password='" + pwd+"'";
Statement stmt = connection.createStatement();// sql注入问题
正解:
/** 第一步:注册驱动 **/
Class.forName("com.mysql.jdbc.Driver");
/** 第二步:获取连接 **/
// 协议:数据库类型:子协议 参数:数据库类型,,哪个数据库
String url = "jdbc:mysql://localhost:3306/school"; // http://localhost:80/xx.html 简写:jdbc:mysql:///school
String user = "root";
String password = "1234";
Connection connection = java.sql.DriverManager.getConnection(url, user, password);
/** 第三步:预编译的语句执行者 **/
String sql = "select * from tb_student where username=? and password=?";
PreparedStatement pstmt = connection.prepareStatement(sql);
/** 第四步:设置参数 **/
pstmt.setString(1, "root");
pstmt.setString(2, "1234");
/** 第五步:执行 **/
ResultSet resultSet = pstmt.executeQuery(sql);不能传sql参数 ,如果传了就是调用stmt的方法了!!! pstmt.executeUpdate();
/** 第刘步:数据处理 **/
while (resultSet.next()) {
String string = resultSet.getString("name");
System.out.println(string);
}
关闭连接
if (resultSet != null)
try {
resultSet.close();
} catch (SQLException e) {
// e.printStackTrace(); ignore
} finally {
resultSet = null;
}
if (pstmt != null)
try {
pstmt.close();
} catch (SQLException e) {
// e.printStackTrace(); ignore
} finally {
pstmt = null;
}
if (connection != null)
try {
connection.close();
} catch (SQLException e) {
// e.printStackTrace();
// ignore
} finally {
connection = null;
}
常用类
DriverManager:管理了一组jdbc的操作 类
static Connection getConnection(String url, String user, String password) //获取连接
Connection:连接 接口
Statement createStatement() : //获取普通的语句执行者 会出现sql注入问题
PreparedStatement prepareStatement(String sql) ://获取预编译语句执行者 !!
CallableStatement prepareCall(String sql)://获取调用存储过程的语句执行者
setAutoCommit(false) //手动开启事务
rollback()//事务回滚
commit()//提交事务,关闭自动提交,不提交,所有操作都不无效
SavePoint conn.setSavepoint(); //获得回滚点
rollback(savePoint)//事务回滚,回滚点前的sql还有效
Statement:语句执行者 接口
setXxx(int 第几个问号,Object 实际参数);
resultSet executeQuery() ://执行 r 语句 返回值:结果集
int executeUpdate() ://执行cud 语句 返回值:影响的行数
addBatch(sql);//批处理
executeBatch();
事务隔离级别
问题:
1.脏读:一个事务读另外一个正在进行的事务,另一个可能回滚
2.不可重复读:一个事务多次查询中,另一个事务提交了修改,导致多次查询结果不一样
3.幻读(虚读):一个事务多次查询中,另一个事务提交了插入,删除,,多次查询条数不一样
/**
* Connection.TRANSACTION_READ_UNCOMMITTED 读未提交数据,什么都不能避免
* Connection.TRANSACTION_READ_COMMITTED 读提交后的数据,避免脏读
* Connection.TRANSACTION_REPEATABLE_READ 可重读 ,避免脏读和不可重复读
* Connection.TRANSACTION_SERIALIZABLE 序列化同步(最高级别,等待,单线程),都避免
*/
connection.setAutoCommit(false);//开启事务
connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
ResultSet:结果集 接口
boolean next():判断是否有下一条记录,若有返回true且将光标移到下一行,若没有呢则返回false
getXxx(int|string)
若参数为int :第几列
若参数为string:列名(字段名)
// java->sql 父类 -> 子类 ; 相反 子类->父类 直接赋值
Date date = new java.util.Date(); // 父类
java.sql.Date date2 = new java.sql.Date(date.getTime());
数据库连接池
使用jdbc的时候,每操作一次都需要获取连接(创建)用完之后把连接释放掉了(销毁).
连接池初始化时候,存入一定数量的连接,用的时候通过方法获取,不用的时候归还.减少创建,效果的消耗
方试:
1.继承或实现 (Connection有数据库厂商实现或继承,不可通)
2.装饰者模式(静态代理)
3.动态代理
装饰者模式
1.装饰者和被装饰者实现同一个接口或者继承同一个类
2.装饰者中要有被装饰者的引用
3.对需要增强的方法进行加强
4.对不需要加强的所有方法调用原来方
动态代理
Student sProxy = (Student) java.lang.reflect.Proxy.newProxyInstance(loader, interfaces, h);
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载(一般是)
interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h: 一个InvocationHandler接口的对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
final Student s = new Student();// 被代理对象,,,最好配置文件加载(插卡) Class.forName("").newInstance();
Student sProxy = (Student) java.lang.reflect.Proxy.newProxyInstance(s.getClass().getClassLoader(), s.getClass()
.getInterfaces(), new InvocationHandler() {
// proxy: 指代我们所代理的那个真实对象
// method: 指代的是我们所要调用真实对象的某个方法的Method对象
// args: 指代的是调用真实对象某个方法时接受的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
Object invoke = method.invoke(s, args);
return invoke;
}
});
数据库连接池
所有的连接池必须实现一个接口 javax.sql.DataSource接口
获取连接方法:Connection getConnection()
DataSource
1.导入jar包(commons-dbcp-1.4.jar和commons-pool-1.5.6.jar)
2.使用api
a.硬编码
//创建连接池
BasicDataSource ds = new BasicDataSource();
//配置信息
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql:///day07");
ds.setUsername("root");
ds.setPassword("1234");
b.配置文件
实现编写一个properties文件
//存放配置文件
Properties prop = new Properties();
prop.load(getClass().getClassLoader().getResourceAsStream("jdbc.properties"));
//设置
//prop.setProperty("driverClassName", "com.mysql.jdbc.Driver");
//创建连接池
DataSource ds = new BasicDataSourceFactory().createDataSource(prop);
c3p0
C3P0:
hibernate和spring使用
有自动回收空闲连接的功能.
使用步骤:
1.导入jar包(c3p0-0.9.5.2.jar和mchange-commons-java-0.2.11.jar)
2.使用api
a.硬编码(不推荐)
new ComboPooledDataSource()
b.配置文件
配置文件的名称:c3p0.properties 或者 c3p0-config.xml
配置文件的路径:src下
编码只需要一句话
new ComboPooledDataSource()//使用默认的配置
new ComboPooledDataSource(String configName)//使用命名的配置 若配置的名字
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/xxx
c3p0.user=root
c3p0.password=1234
DbUtils
http://commons.apache.org/proper/commons-dbutils/