jdbc介绍


#JDBC介绍

jdbc介绍

  1. JDBC(Java Data Base Connectivity,java数据库连接)是什么?
  2.  SUN公司为了简化、统一对数据库的操作,定义了一套Java操作数据库的规范,称之为JDBC。
  3. 什么是驱动? 两个设备要进行通信,满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,通过软件可以与该设备进行通信
    如果没有JDBC,Java程序员需要面向各个数据库驱动接口编程,开发复杂 ; sun 公司提供一套统一JDBC接口规范,Java程序只需要使用JDBC就可以操作任何数据库,JDBC实现类由各个数据库厂商提供,
    简单说:就是可以直接通过java语言,去操作数据库。jdbc是一套标准,它是由一些接口与类组成的。
    学习中涉及到的类与接口
    它们主要在两个包下
    java.sql
    类:DriverManger
    接口 Connection Statement ResultSet PreparedStatement
    CallableStatement(它是用于调用存储过程)
    javax.sql
    接口 DataSource
  4. 什么是驱动?
    两个设备要进行通信,满足一定通信数据格式,数据格式由设备提供商规定,设备提供商为设备提供驱动软件,
    通过软件可以与该设备进行通信

jdbc入门

编写一个jdbc入门代码,完成对数据库操作.
	create table user(
	   id int primary key auto_increment,
	   username varchar(20) unique not null,
	   password varchar(20) not null,
	   email varchar(40) not null
	);
	
	INSERT INTO USER VALUES(NULL,'tom','123','tom@163.com');
	INSERT INTO USER VALUES(NULL,'fox','123','fox@163.com');

1.下载驱动
将驱动jar包复制到lib下.
2.创建一个JdbcDemo类

	// 1.注册驱动
	DriverManager.registerDriver(new Driver());

	// 2.获取连接对象
	Connection con = DriverManager.getConnection(
			"jdbc:mysql://localhost:3306/jdbc", "root", "root");

	// 3.通过连接对象获取操作sql语句Statement
	Statement st = con.createStatement();

	// 4.操作sql语句
	String sql = "select * from user";

	// 操作sql语句(select语句),会得到一个ResultSet结果集
	ResultSet rs = st.executeQuery(sql);

	// 5.遍历结果集
	// boolean flag = rs.next(); // 向下移动,返回值为true,代表有下一条记录.
	// int id = rs.getInt("id");
	// String username=rs.getString("username");
	// System.out.println(id);
	// System.out.println(username);
	
	while(rs.next()){
		int id=rs.getInt("id");
		String username=rs.getString("username");
		String password=rs.getString("password");
		String email=rs.getString("email");
		
		System.out.println(id+"  "+username+"  "+password+"  "+email);
	}
	
	//6.释放资源
	rs.close();
	st.close();
	con.close();

jdbc操作详解

注册驱动

DriverManager.registDriver(new Driver());

1.DriverManager类
它是java.sql包下的一个驱动管理的工具类,可以理解成是一个容器(Vector),可以装入很多数据库驱动
它的registDriver方法分析
public static synchronized void registerDriver(java.sql.Driver driver)
参数:java.sql.Driver
我们传递的是 com.mysql.jdbc.Driver;
在com.mysql.jdbc.Driver类中有一段静态代码块:

static {
	try {
		java.sql.DriverManager.registerDriver(new Driver());
	} catch (SQLException E) {
		throw new RuntimeException("Can't register driver!");
	}
}

上述代码的问题:

  1. 在驱动管理器中会装入两个mysql驱动.
    解决方案:使用反射
    Class.forName(“com.mysql.jdbc.Driver”);
    分析:使用反射的方式来加载驱动有什么好处?
    1.只加载一次,装入一个驱动对象.
    2.降低耦合,不依赖于驱动.
  2. 可以通过DriverManager来获取连接对象
    Connection con=DriverManager.getConection(String url,String user,String password);
    url作用:就是用于确定使用哪一个驱动.
    mysql url: jdbc:mysql://localhsot:3306/数据库名.
    oralce url: jdbc:oracle:thin:@localhost:1521:sid
  3. 总结:DriverManager作用:
    1.注册驱动
    2.获取连接Connection
  4. 关于url
    url格式
    主协议 子协议 主机 端口 数据库
    jdbc : mysql 😕/localhost:3306/jdbc
    mysql的url可以简写:
    前提:主机是localhost 端口是3306
    jdbc:mysql:///day17
    了解:在url后面可以带参数
    useUnicode=true&characterEncoding=UTF-8(解决操作数据库乱码问题)

Connection详解

java.sql.Connection,它代表的是一个连接对象。简单说,就是我们程序与数据库连接。
Connection作用:

  1. 可以通过Connection获取操作sql的Statement对象。
    Statement createStatement() throws SQLException
    示例:
    Statement st=con.createStatement();
    了解:
    1.可以获取执行预处理的PreparedStatement对象.
    PreparedStatement prepareStatement(String sql) throws SQLException
    2.可以获取执行存储过程的 CallableStatement
    CallableStatement prepareCall(String sql) throws SQLException
  2. 操作事务
    setAutoCommit(boolean flag);开启事务
    rollback();事务回滚
    commit();事务提交

Statement详解

java.sql.Statement用于执行sql语句.
Statement作用:

  1. 执行sql
    DML:insert update delete
    int executeUpdate(String sql)
    利用返回值判断非0来确定sql语句是否执行成功。
    DQL:select
    ResultSet executeQuery(String sql)
    可以通过execute方法来执行任何sql语句.
    execute(String sql):用于向数据库发送任意sql语句
  2. 批处理操作
    addBatch(String sql); 将sql语句添加到批处理
    executeBatch();批量执行
    clearBatch();清空批处理.

ResultSet详解

java.sql.ResultSet它是用于封装select语句执行后查询的结果。
常用API

  1. next()方法
    public boolean next();
    用于判断是否有下一条记录。如果有返回true,并且让游标向下移动一行。
    如果没有返回false.
  2. 可以通过ResultSet提供的getXxx()方法来获取当前游标指向的这条记录中的列数据。
    常用:
    getInt()
    getString()
    getDate()
    getDouble()
    参数有两种
    1.getInt(int columnIndex);
    2.getInt(String columnName);
    如果列的类型不知道,可以通过下面的方法来操作
    getObject(int columnIndex);
    getObject(String columnName);

关闭资源

  1. Jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet, Statement和Connection对象。
  2. 特别是Connection对象,它是非常稀有的资源,用完后必须马上释放,如果Connection不能及时、正确的关闭,极易导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。
  3. 为确保资源释放代码能运行,资源释放代码也一定要放在finally语句中。

jdbc示例----CURD

  1. 查询
    1.查询全部
    2.条件查询—根据id
  2. 修改
  3. 删除
  4. 添加
    关于JdbcUtils抽取:
	//只抽取到Connection。
	
	public static Connection getConnection() throws ClassNotFoundException,
		SQLException {

	Class.forName("com.mysql.jdbc.Driver");

	// 获取连接
	Connection con = DriverManager.getConnection("jdbc:mysql:///jdbc",
			"root", "root");

	return con;
	}

关于上述的抽取JdbcUtils的缺点:
1.它只能针对于mysql数据库。
2.每一次调用,都会注册一次驱动.
对于上述问题,对JdbcUtils进行修改:
1.将关于连接数据库的信息定义到配置文件中。
读取配置文件进行加载.

	public class JdbcUtils {
	
		private static final String DRIVERCLASS;
		private static final String URL;
		private static final String USERNAME;
		private static final String PASSWORD;
	
		static {
			DRIVERCLASS = ResourceBundle.getBundle("jdbc").getString("driverClass");
			URL = ResourceBundle.getBundle("jdbc").getString("url");
			USERNAME = ResourceBundle.getBundle("jdbc").getString("username");
			PASSWORD = ResourceBundle.getBundle("jdbc").getString("password");
		}
	
		static {
			try {
				// 将加载驱动操作,放置在静态代码块中.这样就保证了只加载一次.
				Class.forName(DRIVERCLASS);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
	
		public static Connection getConnection() throws SQLException {
	
			// 2.获取连接
			Connection con = DriverManager.getConnection(URL, USERNAME, PASSWORD);
	
			return con;
		}
	}

滚动结果集

默认得到的ResultSet它只能向下遍历(next()),对于ResultSet它可以设置成是滚动的,可以向上遍历,
或者直接定位到一个指定的物理行号.
问题:怎样得到一个滚动结果集?
Statement st=con.createStatement();
ResultSet rs=st.executeQuery(sql);

这是一个默认结果集:只能向下执行,并且只能迭代一次。
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery(sql);

这个就可以创建滚动结果集.
简单说,就是在创建Statement对象时,不使用createStatement();
而使用带参数的createStatement(int,int)

Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException

  1. resultSetType - 结果集类型,它是 ResultSet.TYPE_FORWARD_ONLY、ResultSet.TYPE_SCROLL_INSENSITIVE 或 ResultSet.TYPE_SCROLL_SENSITIVE 之一
  2. resultSetConcurrency - 并发类型;它是 ResultSet.CONCUR_READ_ONLY 或 ResultSet.CONCUR_UPDATABLE 之一
  3. 第一个参数值
    ResultSet.TYPE_FORWARD_ONLY 该常量指示光标只能向前移动的 ResultSet 对象的类型。
    ResultSet.TYPE_SCROLL_INSENSITIVE 该常量指示可滚动但通常不受 ResultSet 底层数据更改影响的 ResultSet 对象的类型。
    ResultSet.TYPE_SCROLL_SENSITIVE 该常量指示可滚动并且通常受 ResultSet 底层数据更改影响的 ResultSet 对象的类型。
  4. 第二个参数值
    ResultSet.CONCUR_READ_ONLY 该常量指示不可以更新的 ResultSet 对象的并发模式。
    ResultSet.CONCUR_UPDATABLE 该常量指示可以更新的 ResultSet 对象的并发模式。
  5. 以上五个值,可以有三种搭配方式
    ResultSet.TYPE_FORWARD_ONLY ResultSet.CONCUR_READ_ONLY 默认
    ResultSet.TYPE_SCROLL_INSENSITIVE ResultSet.CONCUR_READ_ONLY
    ResultSet.TYPE_SCROLL_SENSITIVE ResultSet.CONCUR_UPDATABLE
  6. 常用API
    next():移动到下一行
    previous():移动到前一行
    absolute(int row):移动到指定行
    beforeFirst():移动resultSet的最前面
    afterLast() :移动到resultSet的最后面
    updateRow() :更新行数据

DAO模式

DAO模式(Data Access Object 数据访问对象):在持久层通过DAO将数据源操作完全封装起来,业务层通过操作Java对象,完成对数据源操作
业务层无需知道数据源底层实现 ,通过java对象操作数据源

DAO模式结构 :
1、数据源(MySQL数据库)
2、Business Object 业务层代码,调用DAO完成 对数据源操作
3、DataAccessObject 数据访问对象,持久层DAO程序,封装对数据源增删改查,提供方法参数都是Java对象
4、TransferObject 传输对象(值对象) 业务层通过向数据层传递 TO对象,完成对数据源的增删改查
使用dao模式完成登录操作
1.web层(表现层)
login.jsp LoginServlet User
2.service层(业务层)
UserService
3.dao层(持久层)
UserDao
登录操作:
登录操作
注册操作:
注册操作

sql注入

由于没有对用户输入进行充分检查,而SQL又是拼接而成,在用户输入参数时,在参数中添加一些SQL 关键字,达到改变SQL运行结果的目的,也可以完成恶意攻击。
示例:
在输入用户名时 tom’ or ‘1’='1
这时就不会验证密码了。

String sql = select * from user where username ='' and password ='' ;

例如:
一、输入 username: 老李' or '1'='1    password 随意
select * from user where username ='老李' or '1'='1' and password =''; 
* and 优先级 执行 高于 or 

解决方案:
PreparedStatement(重点)
它是一个预处理的Statement,它是java.sql.Statement接口的一个子接口。
总结PreparedStatement使用:

  1. 在sql语句中,使用"?"占位
    String sql=“select * from user where username=? and password=?”;
  2. 得到PreparedStatement对象
    PreparedStatement pst=con.prepareStatement(String sql);
  3. 对占位符赋值
    pst.setXxx(int index,Xxx obj);
    例如:
    setInt()
    setString();
    参数index,代表的是"?"的序号.注意:从1开始。
    4.b执行sql
    DML: pst.executeUpdate();
    DQL: pst.executeQuery();
    注意:这两方法无参数
    关于PreparedStatement优点:
    1.解决sql注入(具有预处理功能)
    2.不需要在拼sql语句。

jdbc处理大数据

 在实际开发中,程序需要把大文本 Text 或二进制数据 Blob保存到数据库。
 Text是mysql叫法,Oracle中叫Clob
 基本概念:大数据也称之为LOB(Large Objects),LOB又分为:
• clob和blob
• clob用于存储大文本。Text
• blob用于存储二进制数据,例如图像、声音、二进制文等。
 对MySQL而言只有blob,而没有clob,mysql存储大文本采用的是Text,Text和blob分别又分为:
blob 大二进制
TINYBLOB(255)、BLOB(64kb)、MEDIUMBLOB(16m)和LONGBLOB(4g)
text(clob) 大文本
TINYTEXT(255)、TEXT(64kb)、MEDIUMTEXT(16m)和LONGTEXT(4g)

对于大数据操作,我们一般只有两种 insert select
演示1:
大二进制操作:

  1. 建表
    create table myblob(
    id int primary key auto_increment,
    content longblob
    )
  2. 向表中插入数据
    问题1:java.lang.AbstractMethodError: com.mysql.jdbc.PreparedStatement.setBinaryStream(ILjava/io/InputStream;)V
    原因:mysql驱动不支持setBinaryStream(int,InputStream);
    修改成
    pst.setBinaryStream(1, fis,file.length());
    原因:因为mysql驱动不支持setBinaryStream(int,InputStream,long);
    解决:
    mysql驱动支持setBinaryStream(int,InputStream,int);
    注意:如果文件比较大,那么需要在my.ini文件中配置
    max_allowed_packet=64M
    总结:

    pst.setBinaryStream(1, fis, (int) (file.length()));

    InputStream is = rs.getBinaryStream(“content”);

演示2:

  1. 存储大文本:建表
    create table mytext(
    id int primary key auto_increment,
    content longtext
    )
  2. 存储
    File file = new File(“D:\java1110\workspace\jdbc\abc.txt”);
    FileReader fr = new FileReader(file);
    pst.setCharacterStream(1, fr, (int) (file.length()));
  3. 获取:
    Reader r = rs.getCharacterStream(“content”);

jdbc批处理

一次可以执行多条sql语句
在jdbc中可以执行sql语句的对象有Statement,PreparedStatement,它们都提供批处理.

  1. Statement执行批处理
    addBatch(String sql); 将sql语句添加到批处理
    executeBatch(); 执行批处理
    clearBatch();清除批处理命令
    优点:可以向数据库发送多条不同的SQL语句。
    缺点
     SQL语句没有预编译。
     当向数据库发送多条语句相同,但仅参数不同的SQL语句时,需重复写上很多条SQL语句。例如:
    Insert into user(name,password) values(‘aa’,’111’);
    Insert into user(name,password) values(‘bb’,’222’);
    Insert into user(name,password) values(‘cc’,’333’);
    Insert into user(name,password) values(‘dd’,’444’);

  2. PreparedStatement执行批处理
    addBatch();将sql语句添加到批处理
    executeBatch();执行批处理命令
    clearBatch();清除批处理命令
    优点:发送的是预编译后的SQL语句,执行效率高。
    缺点:只能应用在SQL语句相同,但参数不同的批处理中。因此此种形式的批处理经常用于在同一个表中批量插入数据,或批量更新表的数据。

  3. 以上两个对象执行批处理区别?
    1.Statement它更适合执行不同sql的批处理。它没有提供预处理功能,性能比较低。
    2.PreparedStatement它适合执行相同sql的批处理,它提供了预处理功能,性能比较高。

  4. 注意;mysql默认情况下,批处理中的预处理功能没有开启,需要开启
    1. 在 url下添加参数
    url=jdbc:mysql:///jdbc?useServerPrepStmts=true&cachePrepStmts=true&rewriteBatchedStatements=true
    2. 注意驱动版本
    Mysql驱动要使用mysql-connector-java-5.1.13以上

  5. 默认使用PreparedStatement是不能执行预编译的,这需要在url中给出useServerPrepStmts=true参数(MySQL Server 4.1之前的版本是不支持预编译的,而Connector/J在5.0.5以后的版本,默认是没有开启预编译功能的)。
    例如:jdbc:mysql://localhost:3306/test?useServerPrepStmts=true
    这样才能保证mysql驱动会先把SQL语句发送给服务器进行预编译,然后在执行executeQuery()时只是把参数发送给服务器。
    当使用不同的PreparedStatement对象来执行相同的SQL语句时,还是会出现编译两次的现象,这是因为驱动没有缓存编译后的函数key,导致二次编译。如果希望缓存编译后函数的key,那么就要设置cachePrepStmts参数为true。例如:
    jdbc:mysql://localhost:3306/test?useServerPrepStmts=true&cachePrepStmts=true
    MySQL的批处理也需要通过参数来打开:rewriteBatchedStatements=true
    例如:jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
    Mysql驱动要使用mysql-connector-java-5.1.13以上

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值