一,对JDBC的认识
Jdbc是一个持久层技术,它特定独立于数据库管理系统,通用的sql数据库存储操作的公共api,是访问数据库的一种规范和标准的接口,定义了java访问数据库的标准类库(如java.sql,javax.sql),jdbc可以方便访问数据库并操作数据库,jdbc也在其他语言中有同样的作用
jdbc带来的好处:
1,jdbc为访问不同sql数据库提供了统一的途径(通过jdbc可以访问MySQL和oracle等数据库)
2,jdbc屏蔽了底层细节,简化了开发过程
假如没有jdbc我们访问数据库:
我们要根据不同数据库类型,写一个驱动程序,过程复杂,门槛高
jdbc的两类接口:
1,程序操作的API接口:这是面向开发者的接口(开发者根据这是接口实现对数据库的操作)
2,数据库的驱动接口Driver:这是面向数据库厂商的接口(厂商根据jdbc提供的标准开发驱动Driver,实现不同数据库的复用性)
jdbc是持久层框架的基础:
mybatis就是基于jdbc的对象关系型映射框架,还有Hibernate框架……
二,jdbc的操作
jdbc的操作主要是连接+增删改查
一,数据库连接方式
jdbc的数据库的连接方式其实是固定的:注册驱动 -> 通过配置信息建立连接
1,直接创建Driver对象
Driver API
String div="jdbc:mysql://localhost:3306/wql";
Driver driver=new com.mysql.jdbc.Driver(); //直接new Driver对象,耦合度高直接依赖于MySQLjar包
Properties info =new Properties();
info.put("user", "root");
info.put("password", "123");
Connection connection=driver.connect(div, info);
System.out.print(connection);
connection.close();
2,反射创建Driver对象
通过class反射创建对象
class API
Driver driver=(Driver) Class.forName("com.mysql.jdbc.Driver").newInstance();//其实没必要这样,forname返回的是静态类,直接调用就行
String con="jdbc:mysql://localhost:3306/WQL";
Properties properties=new Properties();
properties.setProperty("user", "root");
properties.setProperty("password", "123");
Connection connection=driver.connect(con,properties);
connection.close();
System.out.print(connection);
3,DriverManager管理类创建连接(常用)
Manager是驱动的管理类可以创建连接,也可以操作其他信息
Driver API
String dirver="com.mysql.jdbc.Driver"; String connection="jdbc:mysql://localhost:3306/WQL"; Class.forName(dirver); Connection conn=DriverManager.getConnection(connection, "root", "123");//也可以转一个properties对象 conn.close(); System.out.print(conn);
4,外部配置文件建立连接
把配置参数写入文件中,在文件中配置修改信息,降低耦合,增加重用性
1,建立一个wql.propertise文件
user=root password=123 Driver=com.mysql.jdbc.Driver connection=jdbc:mysql://localhost:3306/WQL
2,将文件信息读取建立连接
//定义变量
String user=null;
String password=null;
String driver=null;
String connection=null;
//读取配置文件
FileInputStream input=new FileInputStream("wql.properties");
//读取文件流
Properties properties=new Properties();
properties.load(input);
user = properties.getProperty("user");
password = properties.getProperty("password");
driver = properties.getProperty("Driver");
connection=properties.getProperty("connection");
//连接
Driver d = (Driver) Class.forName(driver).newInstance();
Properties properties1=new Properties();
properties1.setProperty("user", user);
properties1.setProperty("password", password);
Connection conn=d.connect(connection,properties1);
//测试连接是否有效
System.out.print(conn);
conn.close();
二,Statement操作数据库
statement是jdbc的操作数对象之一,通过它可以实现对数据的DML操作
一,statement的获取
通过connection连接获取statement对象
Statement statement=conn.createStatement();
二,数据的插入和修改
插入和修改操作都依赖execte方法,在statement操作只能通过sql语句的字符串拼接来实
sql语句的拼接对资源是一种极大的消耗,批量插入或者修改时,字符串都必须重新组装,浪费时间和内存
三,数据的查询
查询依赖executeQuery方法,它返回一个Resultset对象,通过遍历Resultset对象可以查询结果
Statement statemend=conn.createStatement();
String sql="select * from "+tablename;
ResultSet resultset=statemend.executeQuery(sql);
ArrayList<String[]> list=new ArrayList<>();
while(resultset.next()) {
Integer id= resultset.getInt(1);
String name= resultset.getString(2);
Integer random= resultset.getInt(3);
String[] wql=new String[3];
wql[0]=id.toString();
wql[1]=name;
wql[2]=random.toString();
list.add(wql);
}
Iterator l= list.iterator();
while(l.hasNext()) {
String[] a=(String[]) l.next();
for(String aq:a) {
System.out.print(aq+"\t");
}
System.out.println();
}
close(statemend);
resultset.close();
三,PreparedStatement操作数据库
preparedstatement严格上它是statement的子类,它是在statement上的弊端的补全和结构的优化
preparedstatement最大的改良就是把statement的sql字符串拼接改成了参数注入,实现了预编译sql语句,sql语句被预编译进入prepaoedstatement对象中,使用这个对象可以高效的重复执行操作
一,创建preparedstatement对象
connection创建preparedstatement的API
String sql="insert into "+tablename+" values(?,?,?)"; PreparedStatement s=(PreparedStatement) conn.prepareStatement(sql);
二,数据的插入和修改
String sql="insert into "+tablename+" values(?,?,?)"; PreparedStatement s=(PreparedStatement) conn.prepareStatement(sql); // System.out.print(sql); s.setInt(1, 7); s.setString(2, "las"); s.setInt(3, 100); s.executeUpdate();//执行语句 close(s); s.close();
三,数据查询
String sql="select * from ?";
PreparedStatement s= conn.prepareStatement(sql);
s.setString(1, "test");
ResultSet ss= s.executeQuery(sql);
while(ss.next()) {
System.out.print(ss.getString(2)+"===="+ss.getInt("id"));
}
四,statement和preparedstatement的比较
两者区别主要是从安全性和效率两个方面比较:
1,安全性:前者sql的执行主要是通过字符串拼接实现的,容易产生sql注入,而后者是预编译在方法内部运行,不会产生注入问题
2,效率:字符串的拼接本身也是极其浪费资源的,批量操作每一次执行都需要拼接一次字符串浪费了资源,后者预编译sql,可以高效重复执行
一,SQL注入问题
通过字符串的拼接原理,人为产生一个新sql
Statement statement=conn.createStatement(); //注入语句 String sql1="where id>100"; //正常语句 String sql="select * from test"; //注入sql statement.executeQuery(sql+sql1);
二,批量操作
批量操作的几种方式:
1,statement实现
2,preparedstatement实现
3,addbatch缓冲池实现
//批量插入数据
public static void main(String[] args) throws Exception {
jdbctool c=new jdbctool();
Connection conn = c.getconn();
long a= System.currentTimeMillis();
test3(conn);
long a1=System.currentTimeMillis();
System.out.print((a1-a)/1000);
}
//方式1:statement,字符串拼接
public static void test1(Connection conn) throws SQLException {
Statement statement=conn.createStatement();
for(int a=2;a<=100000;a++) {
String sql="insert into test values ("+a+","+a+")";
statement.execute(sql);
}
statement.close();
conn.close();
//花费时间:73秒
}
//方式2:preparedstatement
public static void test2(Connection conn) throws SQLException {
String sql="insert into test values (?,?)";
PreparedStatement prepared =conn.prepareStatement(sql);
for(int i=2;i<=100000;i++) {
prepared.setInt(1, i);
prepared.setString(2,""+i);
prepared.execute();
}
prepared.close();
conn.close();
//花费时间:53秒
}
//方式3:preparedstatement的addbatch缓冲池(相当于io的buffer缓存区)
//注:在sql中默认一条语句就是一个事务直接提交,用缓冲区我们不要自动提交,设置为手动提交(?rewriteBatchedStatements=true加在url配置后面)
public static void test3(Connection conn) throws SQLException {
String sql="insert into test values (?,?)";
PreparedStatement prepared =conn.prepareStatement(sql);
for(int i=2;i<=100000;i++) {//多了个0
prepared.setInt(1, i);
prepared.setString(2, ""+i);
//加入缓冲区
prepared.addBatch();
if(i%50000==0) {
prepared.executeBatch();
prepared.clearBatch();
}
}
prepared.close();
conn.close();
//花费时间:34秒
}
三,Blob类型数据的插入
Blob类型数据算是MySQL中一种有意思的数据类型
blob类型介绍:
1,blob类型是MySQL中一种二进制大型对象,是一个存储大型数据的容器,它能容纳不同大小的数据(像图片和音频)
2,插入blob对象必须要使用PreparedStatement对象,因为它不能通过字符串拼接得到(它的输入有两种:输入io流,blob对象)
3,MySQL中有四种blob类型(除最大容量不同,其他一致)
类型 大小(单位:字节) TinyBlob 最大255 Blob 最大65k MediumBlob 最大16M LongBlob 最大4G
注:如果过大数据库性能会下降,超过容量会报错
PreparedStatement插入blob API:
Connection conn=null;
jdbctool tool=new jdbctool();
conn=tool.getconn();
PreparedStatement prepared = conn.prepareStatement("insert into blobs values (?,?)");
InputStream wql = new FileInputStream(new File("4-1.jpg"));
prepared.setInt(1, 1);
prepared.setBlob(2, wql);
prepared.execute();
prepared.close();
conn.close();
三,数据库连接池
数据库连接创建和关闭读极其耗费资源,而数据库连接池就很好的弥补了这个缺陷,连接池提高了连接的重用性
连接池的作用:
1,统一管理连接创建和销毁,减少资源的占用
2,连接的可重用性提高,提高的程序效率
连接池三种类型jar包下载:
DataSource接口(重点):
这是java提供,数据库连接池的必须实现的一个接口,主要由数据库厂商实现
而DataSource又继承ConnomDatasource方法
常用的连接池框架(主要介绍三种):
1,C3P0:是一个开源组织提供的数据库连接池,速度较慢,但稳定性较好
2,DBCH:Apache提供是Tomcat自带的数据库连接池,相比较C3P0快,当自身有bug
3,Druid:是阿里的连接池,集成了各数据库连接池的优点(是现在主流)
一,C3P0
第一种实现(手写配置):
//获取c3p0连接池,
ComboPooledDataSource pool= new ComboPooledDataSource();
//基本参数设置
pool.setDriverClass("com.mysql.jdbc.Driver");
pool.setJdbcUrl("jdbc:mysql://localhost/wql");
pool.setUser("root");
pool.setPassword("123");
//获取连接
Connection conn=pool.getConnection();
System.out.print(conn);
第二种实现(配置文件配置):
这里配置文件可以是prepaoties文件也可以是xml文件,以xml文件为例
新建一个xml文件:这个文件命名必须是c3p0默认配置文件名,c3p0-config.xml,c3p0有自己独特的xml风格
c3p0-config.xml:文件格式和配置信息详情,只是一部分
<?xml version="1.0" encoding="UTF-8"?>
<!--c3p0根标签 -->
<c3p0-config>
<!--default-config 默认配置 只读取一次 -->
<default-config>
<!-- 连接超时时间 -->
<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用户可以当指定连接数和缓存PreparedStatement的总数 -->
<user-overrides user="test-user">
<property name="maxPoolSize">10</property>
<property name="minPoolSize">1</property>
<property name="maxStatements">0</property>
</user-overrides>
</default-config>
<!--name-config 自定义配置 需要声明name 如果c3p0DataSource调用xml自定义配置需要带name参数 -->
<named-config name="intergalactoApp">
<property name="acquireIncrement">50</property>
<property name="initialPoolSize">100</property>
<property name="minPoolSize">50</property>
<property name="maxPoolSize">1000</property>
<!-- intergalactoApp adopts a different approach to configuring statement caching -->
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
自动文件配置:
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?> <!--c3p0根标签 --> <c3p0-config> <named-config name="wql"> <!--连接元数据信息--> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcurl">jdbc:mysql//localhost:3306/WQL></property> <property name="user">root</property> <property name="password">123</property> <!-- intergalactoApp adopts a different approach to configuring statement caching --> <property name="maxStatements">0</property> <property name="maxStatementsPerConnection">5</property> </named-config> </c3p0-config>
C3P0java文件:
public static void main(String[] args) throws SQLException {
//指定数据名
ComboPooledDataSource pool =new ComboPooledDataSource("wql");
Connection conn=pool.getConnection();
System.out.print(conn);
}


















Comments | 1 条评论
?