新网创想网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
一、JDBC(Java Data Base Connectivity)
从事成都天府联通服务器托管,服务器租用,云主机,虚拟空间,空间域名,CDN,网络代维等服务。
1、数据库驱动:
数据库厂商为了方便开发人员从程序中操作数据库而提供的一套jar包,通过导入这个jar包就可以调用其中的方法操作数据库,这样的jar包就叫做数据库驱动
2、JDBC:
sun定义的一套标准,本质上是一大堆的操作数据库的接口,所有数据库厂商为java设计的数据库驱动都实现过这套接口,这样一来,统一了不同数据库驱动的方法,开发人员只需要学习JDBC就会使用任意数据库驱动了。
六个步骤实现JDBC:
//1.注册数据库驱动
--由于MySQL在Driver类的实现中自己注册了一次,而我们又注册了一次,于是会导致MySql驱动被注册两次。
--创建MySql的Driver对象时,导致了程序和具体的Mysql驱动绑死在了一起,在切换数据库时需要改动java代码。
//DriverManager.registerDriver(new Driver());
Class.forName("com.mysql.jdbc.Driver");
//2.从客户端发出一个和数据库服务端的连接,url=哪台主机哪个端口哪个数据库
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day10", "root", "root");
//3.获取传输器对象。连接=路;传输器=卡车,载数据。
Statement stat = conn.createStatement();
//4.利用传输器传输sql语句到数据库中执行,获取结果集对象
ResultSet rs = stat.executeQuery("select * from user");
//5.遍历结果集获取查询结果
//有一个小游标一行一行的指向结果集,最后一行没东西了返回false
//ResultSet用于代表Sql语句的执行结果。封装执行结果采用的类似于表格的方式。ResultSet对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,第一次调用ResultSet.next()方法,游标指向第一行数据,再次调用ResultSet.next()方法,指向下一行,也就是第二行数据。
while(rs.next()){ String name = rs.getString("name");
System.out.println(name);
}
//6.关闭资源
rs.close();
stat.close();
conn.close();
Connection对象,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机。
为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
try{...... .......
}catch (Exception e) {
e.printStackTrace();
}finally{
//6.关闭资源
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}finally{
rs = null;
}
}
if(stat!=null){
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}finally{
stat = null;
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}finally{
conn = null;
}
}
}
config.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql:///day10
user=root
password=root
JDBCUtils.java
public class JDBCUtils {
private staticProperties prop = null;
private JDBCUtils() {
}
static{
try{
prop = new Properties();
prop.load(new FileReader(JDBCUtils.class.getClassLoader().getResource("config.properties").getPath()));
}catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
//连接
public static ConnectiongetConn()throws ClassNotFoundException, SQLException{
// 1.注册数据库驱动
Class.forName(prop.getProperty("driver"));
// 2.获取连接
return DriverManager.getConnection(prop.getProperty("url"), prop.getProperty("user"), prop.getProperty("password"));
//关闭
public static voidclose(ResultSet rs, Statement stat,Connection conn) {.......}
JDBCDemo2.java
@Test
public void update() {
Connection conn = null;
Statement stat = null;
try{
conn = JDBCUtils.getConn();
stat = conn.createStatement();
stat.executeUpdate("update user set password=999 where name='zhaoliu'");
}catch (Exception e) {
e.printStackTrace();
}finally{
JDBCUtils.close(null, stat, conn);
}
}
层与层耦合的概念,利用工厂类解耦,service如何用dao?DaoFactory.getFactory().getDao();
public class DaoFactory {
private staticDaoFactory factory = new DaoFactory();
private staticProperties prop = null;
static{ try{
prop = new Properties();
prop.load(new FileReader(DaoFactory.class.getClassLoader().getResource("config.properties").getPath()));
}catch (Exception e) { e.printStackTrace();
throw new RuntimeException(e); } }
privateDaoFactory(){ }
public staticDaoFactorygetFactory(){
return factory; }
public UserDaogetDao(){
try{
String clazz = prop.getProperty("UserDao");
return (UserDao) Class.forName(clazz).newInstance();
}catch (Exception e) { e.printStackTrace();
throw new RuntimeException(e); } } }
由于dao中执行的SQL语句是拼接出来的,其中有一部分内容是由用户从客户端传入,所以当用户传入的数据中包含sql关键字时,就有可能通过这些关键字改变sql语句的语义,从而执行一些特殊的操作,这样的***方式就叫做sql注入***
利用预编译的机制将sql语句的主干和参数分别传输给数据库服务器,从而使数据库分辨的出哪些是sql语句的主干哪些是参数,这样一来即使参数中带了sql的关键字,数据库服务器也仅仅将他当作参数值使用,关键字不会起作用,从而从原理上防止了sql注入的问题
PreparedStatement主要有如下的三个优点:
1.可以防止sql注入
2.由于使用了预编译机制,执行的效率要高于Statement
3.sql语句使用?形式替代参数,然后再用方法设置?的值,比起拼接字符串,代码更加优雅.
数据库中存储的是大数据的路径,大数据存在硬盘上,从数据库读大数据费时费力。
了解即可
*JDBC大数据
Text Blob
1.1设置Text类型
PreparedStatement.setCharacterStream(index, reader, length);
//注意length长度须设置,并且设置为int型
//当包过大时修改配置:[mysqld] max_allowed_packet=64M
1.2获取Text类型
reader = resultSet. getCharacterStream(i);
2.1设置BLOB数据类型
PreparedStatement. setBinaryStream(i, inputStream, length);
2.1获取BLOB类型
InputStream in = resultSet.getBinaryStream(i);
InputStream in = resultSet.getBlob(i).getBinaryStream();
public class BlobDemo1 {
@Test
public void findBlob(){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
conn = JDBCUtils.getConn();
ps = conn.prepareStatement("select * from blobdemo");
rs = ps.executeQuery();
while(rs.next()){
String name = rs.getString("name");
InputStream in = rs.getBinaryStream("content");
OutputStream out = new FileOutputStream(name);
byte [] bs = new byte[1024];
int i = 0;
while((i=in.read(bs))!=-1){
out.write(bs,0,i);
}
in.close();
out.close();
}
}catch (Exception e) {
e.printStackTrace();
}finally{
JDBCUtils.close(rs, ps, conn);
}
}
@Test
public void addBlob(){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
conn = JDBCUtils.getConn();
ps = conn.prepareStatement("insert into blobdemo values (null,?,?)");
ps.setString(1, "洛天依.mp3");
File file = new File("1.mp3");
ps.setBinaryStream(2, new FileInputStream(file),(int)file.length());
ps.executeUpdate();
}catch (Exception e) {
e.printStackTrace();
}finally{
JDBCUtils.close(rs, ps, conn);
}
}
}
业务场景:当需要向数据库发送一批SQL语句执行时,应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率。
Statement.addBatch(sql) 执行批处理SQL语句
executeBatch()方法:执行批处理命令
clearBatch()方法:清除批处理命令
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtil.getConnection();
String sql1 = "insert into person(name,password,email,birthday)
values('kkk','123','abc@sina.com','1978-08-08')";
String sql2 = "update user set password='123456' where id=3";
st = conn.createStatement();
st.addBatch(sql1); //把SQL语句加入到批命令中
st.addBatch(sql2); //把SQL语句加入到批命令中
st.executeBatch();
} finally{
JdbcUtil.free(conn, st, rs);
}
采用Statement.addBatch(sql)方式实现批处理:
优点:可以向数据库发送多条不同的SQL语句。
缺点:
SQL语句没有预编译。
当向数据库发送多条语句相同,但仅参数不同的SQL语句时,需重复写上很多条SQL语句。
PreparedStatement.addBatch()
conn = JdbcUtil.getConnection();
String sql = "insert into person(name,password,email,birthday) values(?,?,?,?)";
st = conn.prepareStatement(sql);
for(int i=0;i<50000;i++){
st.setString(1, "aaa" + i);
st.setString(2, "123" + i);
st.setString(3, "aaa" + i + "@sina.com");
st.setDate(4,new Date(1980, 10, 10));
st.addBatch();
if(i%1000==0){
st.executeBatch();
st.clearBatch();
}
}
st.executeBatch();
采用PreparedStatement.addBatch()实现批处理
优点:发送的是预编译后的SQL语句,执行效率高。
缺点:只能应用在SQL语句相同,但参数不同的批处理中。因此此种形式的批处理经常用于在同一个表中批量插入数据,或批量更新表的数据。