Jdbc
jdbc的概念
Java数据库连接,(Java Database Connectivity,简称JDBC) 是java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了查询和更新数据库的方法.
通俗来讲就是: jdbc就是java操作数据库
连接数据库(7大步骤)
- 导入jar包
- 注册驱动
Class.forName("com.mysql.jdbc.Driver");
-
Interface Driver
每个驱动程序类必须实现的接口。
-
Class.forName()将对应的驱动类加载到内存中,然后执行内存中的static静态代码段,代码段中,会创建一个驱动Driver的实例,放入DriverManager中,供DriverManager使用。
-
DriverManager 驱动程序管理器是负责管理驱动程序的,驱动注册以后,会保存在DriverManager中的已注册列表中后续的处理就可以对这个列表进行操作.
jdk4.0以后不需要注册驱动
- 获取执行者
Connection connection = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/mayikt?serverTimezone=UTC",
"root", "1111");
- Interface Connection
连接java应用程序与数据库之间的会话.
Connection接口是Statement,PreparedStatement和DatabaseMetaData的工厂 - 常用方法
1)public Statement createStatement():
创建一个可用于执行SQL查询的语句对象。
2)public Statement prepareStatement() :
创建具有或不具有IN参数的SQL语句可以预编译并存储在PreparedStatement对象中。 然后可以使用该对象多次有效地执行此语句. - 事务相关
3)public void setAutoCommit(boolean status):
用于设置提交状态,默认为true
4)public void commit():
保存自上次提交/回滚永久以来所做的更改。
5)public void rollback():
删除自上一次提交/回退以来所做的所有更改。
6)public void close():
关闭连接并立即释放JDBC资源。
- 获取执行者对象
Statement statement = connection.createStatement();
Interface Statement
1)建立了到特定数据库的连接之后,就可用该连接发送 SQL 语句。
使用上面的 : 1)public Statement createStatement():创建一个可用于执行SQL查询的语句对象。
为了执行 Statement 对象,被发送到数据库的 SQL 语句将被作为参数提供给 Statement 的方法:
ResultSet rs = stmt.executeQuery(“SELECT a, b, c FROMTable2”);
2)Statement 接口提供了三种执行 SQL 语句的方法:executeQuery、executeUpdate 和execute。
方法 executeQuery :
用于产生单个结果集的语句,例如 SELECT 语句。
方法 execute用于执行返回多个结果集、多个更新计数或二者组合的语句.
执行语句的所有方法都将关闭所调用的 Statement 对象的当前打开结果集(如果存在)。这意味着在重新执行 Statement对象之前,需要完成对当前 ResultSet 对象的处理。
继承了 Statement 接口中所有方法的 PreparedStatement 接口都有自己的executeQuery、executeUpdate 和 execute 方法。Statement 对象本身不包含 SQL语句,因而必须给 Statement.execute 方法提供 SQL 语句作为参数。PreparedStatement 对象并 不将SQL 语句作为参数提供给这些方法,因为它们已经包含预编译 SQL 语句。CallableStatement 对象继承这些方法的PreparedStatement 形式。
- 执行SQL语句获取返回结果
ResultSet resultSet = statement.executeQuery("select * from mayikt_users");
Interface ResultSet
- 结果集(ResultSet)是数据中查询结果返回的一种对象,可以说结果集是一个存储查询结果的对象,但是结果集并不仅仅具有存储的功能,他同时还具有操纵数据的功能,可能完成对数据的更新等。
- getXXX可以代表的类型有:基本的数据类型如整型(int),布尔型(Boolean),浮点型(Float,Double)等,比特型(byte),还包括一些特殊的类型,如:日期类型(java.sql.Date),时间类型(java.sql.Time),时间戳类型 (java.sql.Timestamp),大数型(BigDecimal和BigInteger等)等。
- getArray(int colindex/String columnname),通过这个方法获得当前行中,colindex所在列的元素组成的对象的数组。
- getAsciiStream ( int colindex/String colname ) 可以获得该列对应的当前行的ascii流。也就是说所有的getXXX方法都是对当前行进行操作。
- 1.最基本的ResultSet。
之所以说是最基本的ResultSet是因为,这个ResultSet他起到的作用就是完成了查询结果的存储功能,而且只能读去一次,不能够来回的滚动读取。这种结果集的创建方式如下:
Statement st = conn.CreateStatement
ResultSet rs = Statement.excuteQuery(sqlStr);
由于这种结果集不支持,滚动的读去功能所以,如果获得这样一个结果集,只能使用它里面的next()方法,逐个的读去数据。
2、 可滚动的ResultSet类型。
这个类型支持前后滚动取得纪录next()、previous(),回到第一行first(),同时还支持要去的ResultSet中的第几行 absolute(int n),以及移动到相对当前行的第几行relative(int n),要实现这样的ResultSet在创建Statement时用如下的方法。
Statement st = conn. createStatement (int resultSetType, int
resultSetConcurrency) ResultSet rs = st.executeQuery(sqlStr)
其中两个参数的意义是:
resultSetType 是设置 ResultSet 对象的类型可滚动,或者是不可滚动。取值如下:
ResultSet.TYPE_FORWARD_ONLY 只能向前滚动
ResultSet.TYPE_SCROLL_INSENSITIVE 和 Result.TYPE_SCROLL_SENSITIVE 这两个方法都能够实现任意的前后滚动,使用各种移动的 ResultSet 指针的方法。二者的区别在于前者对于修改不敏感,而后者对于修改敏感。
- 对返回结果进行处理
while (resultSet.next()) {
System.out.println(resultSet.getInt("id") + "," + resultSet.getString("name") + "," +
resultSet.getString("pwd"));
}
不可滚动的result的next方法
- 释放资源
connection.close();
statement.close();
Statement和PreparedStatement的区别
- 关系:
PreparedStatement继承自Statement,都是接口. - 区别:
PreparedStatement可以使用占位符,表示预编译的SQL语句对象,批量处理效率比Statement高.
Statement: 用于执行静态的SQL语句并返回它所生成结果的对象,SQL语句之间存在拼接. - 这就会导致SQL注入攻击:原理就是: 通过传递参数(or =1) 拼接的SQL语句 导致其成立可以查询到数据.
- 解决办法: 使用PreparedStatement(预编译执行对象),在SQL语句执行之前,将SQL语句进行提前编译,明确SQL语句格式之后,传递参数.
单元测试的使用步骤
- 导入jar包(junit核心包以及依赖包)
iIdea自带jar包,直接AIT=Enter一键生成 - 针对某个类进行----单元测试----测试功能
@Before
完成初始化操作
@Test
测试方法
@After
执行单元测试方法后,释放资源
util date和sql date的转换
String转util data:
String str="2002-04-19";
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date parse = simpleDateFormat.parse(str);
util data转sql data
java.sql.Date? sqlDate = new
java.sql.Date(utilsData.getTime());
Jdbc数据库连接池
- 我们在jdbc编程中,每次创建断开Connection对象都会消耗一定的时间和IO资源.如果我们频繁的和数据库连接,该过程效率很低.因为在java程序与数据库之间建立连接时,数据库端要验证用户名和密码,并且要为这个连接分配资源,java程序则要把代表连接的java.sql.Connection对象等加载到内存,所以建立数据库连接的开销很大.
- 为了避免频繁的创建数据库连接,与时我们可以通过数据库连接池负责分配,管理和释放数据库连接,它允许程序重复使用现有的数据库连接,而不是重新建立.
- 数据库连接池大致实现原理:
数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,当程序访问数据时不是直接创建Connection,而是向连接池"申请"一个Connection.如果连接池中有空闲Connection,则将其返回,否则创建新的Connection.使用完毕后不会释放资源,而是连接池将Connection回收,并交付其他的线程复用,以减少创建和断开数据库连接的次数,提高数据库的访问效率.
Druid(德鲁伊)
数据库连接池实现技术
ThreadLocal简介
ThreadLocal叫做线程变量,意思是ThreadLocal填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量.ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的变量.
注意:
因为每个Thread内有自己的实例副本,且该副本只能由当前Thread使用.这是ThreadLocal命名的由来.
既然每个Thread有自己的实例副本,且其他Thread不可访问,那就不存在多线程间共享的问题.
ThreadLocal提供了线程本地的实例.它与普通变量的区别在于,每个使用该变量的线程都会初始化一个独立完全的实例副本.ThreadLocal变量通常被private static修饰.当一个线程结束时,它所使用的的所有ThreadLocal相对的实例副本都可被回收.
总的来说,ThreadLocal适用于每个线程需要自己独立的实例需要在多个方法中被使用,也即该变量在线程间隔离而在方法或类间共享的场景
ThreadLocal的原理
- ThreadLocal的set()方法:
public void set(T value) {
//1、获取当前线程
Thread t = Thread.currentThread();
//2、获取线程中的属性 threadLocalMap ,如果threadLocalMap 不为空,
//则直接更新要保存的变量值,否则创建threadLocalMap,并赋值
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
// 初始化thradLocalMap 并赋值
createMap(t, value);
}
ThreadLocal set赋值首先会获取当前线程thread,并获取thread线程中的ThreadLocalMap属性.如果map属性不为空,则直接更新value值,如果为空,则实例化threadLocalMap,并将value值初始化.
ThreadLocalMap和createMap作用
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
ThreadLocalMap是ThreadLocal的内部静态类,而它的构成主要是用Entry来保存数据,而且还是继承的弱引用.在Entry内部使用ThreadLocal作为key,使用我们设置value作为value.
//这个是threadlocal 的内部方法
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
//ThreadLocalMap 构造方法
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
- ThreadLocal的get方法
public T get() {
//1、获取当前线程
Thread t = Thread.currentThread();
//2、获取当前线程的ThreadLocalMap
ThreadLocalMap map = getMap(t);
//3、如果map数据不为空,
if (map != null) {
//3.1、获取threalLocalMap中存储的值
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//如果是数据为null,则初始化,初始化的结果,TheralLocalMap中存放key值为threadLocal,值为null
return setInitialValue();
}
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
- ThreadLocal的remove()方法
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
创建工具类
- 导包
- 定义配置文件
#加载数据库驱动
#driverClassName=com.mysql.jdbc.Driver
#连接数据库的url
url=jdbc:mysql://127.0.0.1:3306/mysqlstudent?useUnicode=true&characterEncoding=UTF-8
#用户名
username=root
#密码
password=1111
#初始化连接数量
initialSize=5
#最大连接数量
maxActive=10
#最大等待时间
maxWait=3000 - 绑定线程创建工具类
//jdbc_druid工具类
public class DruidUtils {
//1.声明数据库源
private static DataSource ds = null;
//2.模拟线程:定义ThreadLocal变量
private static ThreadLocal<Connection> tl = new ThreadLocal<>();
//3.构造方法私有化
public DruidUtils() {
}
//4.静态代码块
static {
try {
//4.1.通过IO流,工具类一加载直接获取jdbc.properties文件
InputStream in = DruidUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
//4.2.创建属性集合存储驱动
Properties properties = new Properties();
properties.load(in);
//4.3.获取连接池对象
ds = DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//5.获取数据源
public static DataSource getDaraSours() {
return ds;
}
//6.从连接池中获取对象
public static Connection getConnection() {
try {
//6.1从当前线程获取Connection
Connection conn = tl.get();
//6.2判断当前线程有没有连接对象
if (conn == null) {
//6.3从数据库源获取连接对象
conn = ds.getConnection();
//6.4通过ThreadLocal的setXX方法给将Connection对象赋给ThreadLocalMap的value
tl.set(conn);
}
return conn;
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
//7.释放资源
//7.1针对DDL,DML,DQL语句
public static void close(ResultSet rs, PreparedStatement ps, Connection conn) {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if (ps != null) {
ps.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if (conn != null) {
conn.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
//7.2针对DDL,DML语句
public static void close(PreparedStatement ps, Connection conn) {
close(null, ps, conn);
}
}
Common Dbutils详解
1.介绍
Common Dbutils是Apache组织提供的一个开源JDBC工具类.
2.API介绍
两个核心类库:
- org.apache.commons.dbutils.DbUtils
- org.apache.commons.dbutils.QueryRunner和一个接口
org.apache.commons.dbutils.ResultSetHandler
3.1DbUtils类
- 做一些关闭连接,装载JDBC驱动程序之类提供方法的类,所有方法都是静态方法
- 重要方法:
1.close(…) : DbUtils类提供了三个重载关闭方法
2.closeQuietly(…)
3.CommitAndCloseQuietly(Connection conn):这一方法用来提交连接,然后关闭连接
4.boolean loadDriver(java.lang.String driverClassName):这一方法装载并注册JDBC驱动程序,如果成功就返回true。使用这种方法,你不需要去捕捉这个异常ClassNotFoundException。
3.2QueryRunner类
- 这个类简化了执行SQL查询,它与ResultSetHandler组合在一起使用就可能完成大部分的数据库操作
- 提供了两个构造方法:一个是默认的构造方法;另一个需要一个javax.sql.DataSource来作为参数
- 主要方法:
1.Object query(Connection conn, String sql,Object[] params, ResultSetHandler rsh)throws SQLException:执行一个查询操作,在这个查询中,对象数组中的每个元素值被用来作为查询语句的置换参数。该方法它会内在地处理PreparedStatement和ResultSet的创建和关闭。最重要的是参数ResultSetHandler会把从ResultSet中获得的数据转换成一个更容易的或是应用程序特定的格式供我们使用。
2.Objectquery(String sql, Object[] params, ResultSetHandler rsh)throws SQLException: 这几乎与第一种方法一样;唯一的不同在于它不将数据库连接提供给方法,并且它是从提供给构造方法的数据源(DataSource)或使用的setDataSource方法中重新获得的。
3.Objectquery(Connection conn, String sql, ResultSetHandler rsh)throws SQLException: 执行一个不需要置换参数的查询操作。
4.intupdate(Connection conn, String sql,Object[] params)throws SQLException:用来执行一个更新(插入、更新或删除)操作。
5.int update(Connection conn,String sql) throws SQLException:用来执行一个更新操作,不需要置换参数。
3.3ResultSetHandler接口
- 这一接口执行处理一个jaca.sql.ResultSet,将数据按要求转换为另一种形式,ResultSetHandler接口提供了一个单独的方法:Object handle (java.sql.ResultSet .rs)。因此任何ResultSetHandler的执行需要一个结果集(ResultSet)作为参数传入,然后才能处理这个结果集,再返回一个对象。因为返回类型是java.lang.Object,所以除了不能返回一个原始的Java类型之外
- 实现类
- ArrayHandler: 把结果集中第一行数据转成对象数组
- ArrayListHandler: 把结果集中的每一行数据转成一个对象数字,再放到List中
- BeanHandler:将结果集中的第一行数据封装到一个对应的javaBean实例中
- BeanListHandler: 每一行数据封装都封装到javaBean对象中
- ColumnListHandler:将结果集中某一列的数据存放到List中。
- KeyedHandler:将结果集中的每一行数据都封装到一个Map里,然后再根据指定的key把每个Map再存放到一个Map里。
- MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
- MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List
- ScalarHandler:将结果集中某一条记录的其中某一列的数据存成Object