目录
一、JDBC
数据库连接技术(通过Java代码操作数据库)Java DataBase Connectify
1、核心API
Driver :接口,数据库驱动。
Connection:接口,数据库连接对象。
Statement:接口,对数据库进行增删改查的对象。
ResultSet:接口,用来封装满足查询条件的结果集。
DriverManger:类,用来注册和管理数据库驱动的类。
1.1 注册驱动:
Class.forName("com.mysql.jdbc.Driver");
注册驱动
* 从JDK1.6之后,JDBC的版本已经是4.0,可以不用手动注册驱动了。
* Class.forName("com.mysql.jdbc.Driver");该行代码可以省略了,
* 但是一般为了兼容以前的代码,一般还会保留注册驱动的代码。
1.2 连接数据库并获得连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.100.54:3306/test","root","root");
/* 通过DriverManager类提供的方法获得,方法如下:
* static Connection getConnection(String url, String user, String password)
* 与数据库建立连接,获得连接对象。
* url:数据库连接URL字符串
* user:用户名,比如:root
* password:密码,比如:root
数据库连接URL字符串格式:
* JDBC协议:子协议://数据库服务器地址:数据库端口号/数据库名;
* JDBC协议是一个固定的协议:jdbc
* 子协议:数据库厂商的名称,比如Mysql数据库子协议:mysql
* MySQL数据库的URL字符串格式
* jdbc:mysql://localhost:3306/day24
* 简化格式:
* jdbc:mysql:///数据名;
* 前提条件:服务器必须是本机,端口号默认是3306
*/
//获得statement声明对象
Statement stmt = conn.createStatement
String sql = "------------";
//执行SQL语句
int row = stmt.excuteUpdate(sql)//对数据库进行增删改操作,返回被影响的行数
Resultset rs = stmt.excuteQuery(sql)//对数据库进行查询操作,返回一个结果
rs.next();//指针下移一行,且判定当前是否有记录,返回一个boolean值
rs.get(列名)

1.3 JDBC之数据库工具类(JDBCUtil)
/**
* JDBC的工具类
*/
public class JDBCUtil {
private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost:3308/test";
private static final String USER = "root";
private static final String PASSWORD = "root";
// 在类加载的时候会执行一次
static {
try {
// 注册驱动
Class.forName(DRIVER_CLASS);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获得连接对象
*/
public static Connection getConnection(){
try {
// 获得连接对象
return DriverManager.getConnection(URL, USER, PASSWORD);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 关闭资源
* @param conn 连接对象
* @param stmt SQL执行对象
*/
public static void close(Connection conn,Statement stmt){
close(conn,stmt,null);
}
/**
* 关闭资源
* @param conn 连接对象
* @param stmt SQL执行对象
* @param rs 结果集对象
*/
public static void close(Connection conn,Statement stmt,ResultSet rs){
try {
if (rs != null)
rs.close(); // 关闭资源
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (stmt != null)
stmt.close(); // 关闭资源
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null)
conn.close(); // 关闭连接
} catch (SQLException e) {
e.printStackTrace();}}}
二、数据库连接池
Java官方为数据库连接池提供了一个接口:javax.sql.DataSource;
只要实现了该接口的类就是连接池,创建该实现类的对象就是连接池对象。
常见的连接池有 C3P0和DBCP
1、C3P0
jar包:c3p0-0.9.2-pre5.jar和mchange-commons-java-0.2.3.jar
1.1 纯代码方式
ComboPooledDataSource ds = new ComboPooledDataSource();// 创建连接池对象
ds.setDriverClass("com.mysql.jdbc.Driver");// 设置数据库参数设置驱动类
ds.setJdbcUrl("jdbc:mysql://10.211.55.3:3306/test");// 设置数据库连接URL字符串
ds.setUser("root");// 设置用户名
ds.setPassword("root");// 设置密码
// 设置连接池参数
ds.setInitialPoolSize(5);// 设置初始连接数
ds.setMaxPoolSize(10);// 设置最大连接数
ds.setCheckoutTimeout(3000);// 设置最大等待时间:毫秒
ds.setMaxIdleTime(2000);// 设置最大空闲时间
for (int i = 0; i < 11; i++) {
Connection conn = ds.getConnection();// 从连接池中获得连接对象
System.out.println(conn);
if(i == 5) {
conn.close();
}}}// 不是真正关闭,而是放回连接池中。
1.2 配置文件方式
文件要求 : 命名为 c3p0-config.xml 直接存储在src目录下
文件内容
<c3p0-config>
<!-- 命名的配置 -->
<named-config name="demo">
<!-- 连接数据库的4项基本参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/db</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 如果池中数据连接不够时一次增长多少个 -->
<property name="acquireIncrement">5</property>
<!-- 初始化连接数 -->
<property name="initialPoolSize">20</property>
<!-- 最小连接受 -->
<property name="minPoolSize">10</property>
<!-- 最大连接数 -->
<property name="maxPoolSize">40</property>
<!-- -JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量 -->
<property name="maxStatements">0</property>
<!-- 连接池内单个连接所拥有的最大缓存statements数 -->
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
<!-- 默认配置,如果没有指定则使用这个配置 -->
<!--
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/db</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
<user-overrides user="test-user">
<property name="maxPoolSize">10</property>
<property name="minPoolSize">1</property>
<property name="maxStatements">0</property>
</user-overrides>
</default-config>
-->
* 使用配置文件使用c3p0:
ComboPooledDataSource ds = new ComboPooledDataSource("demo");// 创建连接池对象:命名配置
for (int i = 0; i < 11; i++) {
Connection conn = ds.getConnection();//从连接池中获得连接对象
System.out.println(conn);
}
// 使用配置文件使用c3p0:默认配置
public static void test02() throws Exception{
ComboPooledDataSource ds = new ComboPooledDataSource();//创建连接池对象:默认配置
for (int i = 0; i < 10; i++) {
Connection conn = ds.getConnection();//从连接池中获得连接对象
System.out.println(conn); if(i == 5) {
conn.close();}}//不是真正关闭,而是放回连接池中。
C3P0连接池工具类
* C3P0连接池工具类
public class C3P0Util {
private static DataSource ds = new ComboPooledDataSource();// 创建数据源
public static DataSource getDataSource(){return ds;}// 返回数据源对象:连接池对象
public static Connection getConnection(){//返回连接对象
try {
return ds.getConnection();
} catch (Exception e) {
throw new RuntimeException(e);
}}}
2、DBCP
jar包:commons-dbcp-1.4.jar:连接池的核心包和commons-pool-1.6.jar:支持包
2.1 纯代码方式
BasicDataSource ds = new BasicDataSource();// 创建连接池对象
ds.setDriverClass("com.mysql.jdbc.Driver");// 设置数据库参数设置驱动类
ds.setUrl("jdbc:mysql://10.211.55.3:3306/test");// 设置数据库连接URL字符串
ds.setUser("root");// 设置用户名
ds.setPassword("root");// 设置密码
// 设置连接池参数
ds.setInitialPoolSize(5);// 设置初始连接数
ds.setMaxActive(10);// 设置最大连接数
ds.setMaxIdle(8);// 最大空闲连接数
ds.setMaxWait(2000);// 最大等待时间
for (int i = 0; i < 11; i++) {
Connection conn = ds.getConnection();// 获得连接对象(重写toString方法)
System.out.println(conn.hashCode());
if(i == 5) {
conn.close();
}} // 将连接对象放回连接池中,等待下一次复用
2.2 配置文件方式
文件要求 : 命名为 xxxx.properties 放在src文件夹下
文件内容
# database connectivity configuration
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.43.47:3308/test
username=root
password=root
# connectivity pool configuration
initialSize=5
maxActive=8
maxIdle=8
maxWait=2000
Properties info = new Properties();// 创建属性集合
info.load(DBCPDemo01.class.getResourceAsStream("/dbcp.properties"));
DataSource ds = BasicDataSourceFactory.createDataSource(info);// 创建连接池对象
for (int i = 0; i < 9; i++) {
Connection conn = ds.getConnection();// 获得连接对象(重写toString方法)
System.out.println(conn.hashCode());
if(i == 5) {
conn.close();
}}}// 将连接对象放回连接池中,等待下一次复用
2.3 DBCP连接池工具类
// DBCP连接池工具类
public class DBCPUtil {
private static DataSource ds;//数据源对象
static {// 静态代码块中创建数据源对象
try {
Properties info = new Properties();// 创建属性集合
info.load(DBCPDemo01.class.getResourceAsStream("/dbcp.properties"));
ds = BasicDataSourceFactory.createDataSource(info);// 创建连接池对象
} catch (Exception e) { e.printStackTrace();}}
public static DataSource getDataSource(){return ds;}//返回数据源方法
public static Connection getConnection(){//返回连接对象
try {
return ds.getConnection();
} catch (Exception e) {
throw new RuntimeException(e);
}}}
2.4 DbUtils
可以简化JDBC复杂的代码操作
jar包:commons-dbutils-1.6.jar和commons-logging-1.1.3.jar
Query Runner:类,可以简化对数据库的增删改查操作的代码;
ResultSetHandler:接口, 提供了封装结果集的策略;
DBUtils:工具,提供了与关闭资源和事务处理相关的方法.
DbUtils.closeQuietly(conn);// 安静的关闭连接对象:不抛出异常
QueryRunner qr = new QueryRunner(DBCPUtil.getDataSource());// 创建查询器对象
int row = qr.update("delete from user where id = ?;",3);// 执行插入操作
QueryRunner qr = new QueryRunner();// 创建查询器对象
conn = DBCPUtil.getConnection();// 获得连接对象
int row = qr.update(conn,"delete from user where id = ?;",4);// 执行插入操作
(sql,ResultSetHandler.rsh)//查询query
三、ResultSetHandler 接口常用实现类
1、ArrayHandler
将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值。常用于只有一条记录的情况。
// 创建查询器对象
QueryRunner qr = new QueryRunner(DBCPUtil.getDataSource());
// 根据id查询用户信息
Object[] objs = qr.query("select * from user where id = ?;", new ArrayHandler(),1);
System.out.println(Arrays.toString(objs));
2、ArrayListHandler
将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中。
// 根据所有用户信息
List<Object[]> list = qr.query("select * from user;", new ArrayListHandler());
// 遍历集合
for (Object[] objs : list) {
System.out.println(Arrays.toString(objs));
}
3、BeanHandler
将结果集中第一条记录封装到一个指定的JavaBean中。前提:表的列名与JavaBean属性名要相同。常用于只有一条记录的情况。
// 根据所有用户信息
User user = qr.query("select * from user;", new BeanHandler<User>(User.class));
System.out.println(user);
4、BeanListHandler
将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中
// 根据所有用户信息
List<User> users = qr.query("select * from user;", new BeanListHandler<User>(User.class));
for (User user : users) {
System.out.println(user);
}
5、MapHandler
将结果集中第一条记录封装到了Map<String,Object>集合中,key就是字段名称,value就是字段值
// 查询用户信息
Map<String,Object> map = qr.query("select * from user where id = 2;", new MapHandler());
System.out.println(map);
6、MapListHandler
将结果集中每一条记录封装到了Map<String,Object>集合中,key就是字段名称,value就是字段值,再将这些Map封装到List集合中。
// 查询用户信息
List<Map<String,Object> > list = qr.query("select * from user;", new MapListHandler());
for (Map<String, Object> map : list) {
System.out.println(map);
}
7、ColumnListHandler
将结果集中指定的列的字段值封装到一个List集合中。通常用于多行单列的查询结果集.集合中的元素类型与列的类型要相同。
// 查询所有用户姓名
List<String> list = qr.query("select * from user;", new ColumnListHandler<String>("username"));
System.out.println(list);
8、KeyedHandler
将多条记录封装成一个Map,取其中的一列做为键,记录本身做为值,这个值是Map集合,封装这一条记录。即:Map<某列类型,Map<字段名,字段值>>,其中KeyedHandler指定为<某列的类型>(列名)。
// 查询所有用户信息
Map<String,Map<String,Object>> map = qr.query("select * from user;", new KeyedHandler<String>("username"));
Set<Entry<String, Map<String,Object>>> entrySet = map.entrySet();
for (Entry<String, Map<String, Object>> entry : entrySet) {
// 1= {id=1,username=jack,gender=男,address=广州}
// 2= {id=2,username=rose,gender=男,address=深圳}
System.out.println(entry.getKey()+"="+entry.getValue());
}
9、ScalarHandler
把结果集的第一行第一列取出。通常用于只有单行单列的聚合函数查询查询结果集。例如select count(*) from 表操作。
// 查询记录数
long count = qr.query("select count(*) from user;", new ScalarHandler<Long>())
四、事务
-- 将一个业务操作涉及到的多条SQL语句看成一个整体,着多条语句要么全部执行成功,要么全部执行失败,只要有一条语句执行失败,之前已经执行成功的SQL语句撤销执行.
1、MySQL 事务处理方式
自动提交方式:默认值
默认每一天SQL语句执行完之后就会自动提交事务
set autocommit = 0 ----禁止自动提交模式(false) set autocommit = 1 ----开启自动提交模式(true)....默认模式
手动提交模式
start transaction; -- 开启事务 rollback; -- 回滚事务,撤销当前执行成功的SQL语句; commit; --提交事务,不能再回滚
事务结束条件
commit
rollback
执行一条DDL语句,如创建一张表,事务会自动提交
开启一个新的事务,之前的事务会自动提交
connection接口中与事务相关的方法
void setAutoCommit(boolean autoCommit)=> conn.setAutoCommit(false) =>事务开启,手动提交
设置是否自动提交事务
false:手动提交,开启事务,等价于再控制台执行: tart transaction;
true:自动提交事务,默认值
void commit(); 提交事务
void rollback();回滚事务
DBUtils
//回滚事务并关闭连接对象(不会有异常)
DbUtils.rollbackAndCloseQuietly(conn);
//提交事务并关闭连接对象(不会有异常)
DbUtils.commitAndCloseQuietly(conn);
分层开发:
不同的层使用不同的包
数据访问层:
业务逻辑层
表现层
工具类
实体类
测试类
ThreadLocal类(提供了一个可以在线程内共享的局部变量)
结构:底层是一个Map集合,(key = 线程对象, value = 共享的数据)
创建ThreadLocal对象
static ThreadLocal<T> local = new ThreadLocal<T>();
存储数据到local中
local.set(xxx)
system.out.println(local.get());
创建一个子线程对象
new Thread(){//匿名内部类
//重写run方法
public void run(){
//存数据到子线程的local中
local.set(YYY)
};
}.start();
2、事务的特性
2.1 ACID
原子性 :事务的操作是一个不可分割的单元
一致性:事务前后的数据要保存一致
隔离性:事务之间的操作互补影响
持久性:事务一旦提交,则对数据库的影响是永久的,不可逆的
2.2 隔离级别
脏读:一个事务读取到另一个事务未提交的数据一个事务在
不可重复读:一个事务多次读取的数据不一致
幻读:一个事务在查收数据记录时,前后查询不一致.一般由insert/delete引起
隔离级别
read uncommitted:最低隔离级别,存在的问题:脏读,不可重复读,幻读
read committed: 一个事务读取到了另一个事务提交了的数据,存在的问题:不可重复读,幻读 Oracle默认的隔离级别
repeatable read:一个事务多次读取的同一条数据结果一样的,存在的问题:幻读 MySQL默认的隔离级别
serializable:最高隔离级别, 串行化,同一时间只有一个事务在操作
查询全局事务隔离级别:
select @@global.tx_isolation;
设置全局事务隔离级别:
set global transaction isolation level +级别
以上为个人学习总结,如有错漏,希望能得到沟通以及指正,非常感谢!