1.SQL注入问题
create table user( id int(4) primary key auto_increment, username varchar(10) not null, password varchar(15) ); insert into user values(0001,'张三','666666'); insert into user values(0002,'李四','888888'); select*from user where username='' and password =''; select*from user where username='"+username+"' and password ='"+password+"' select*from user where username='张三' and password ='a'or'1'='1'
表示一个永真式
先打断点-》debug as -》F5表示进入方法,F6表示一步步走,F8表示进入下一个断点或者结束
2.连接池技术
数据库连接的建立和关闭,由一定的资源消耗,比较大。
传统的数据库访问方式:一次数据库访问对应一次物理连接,每次操作数据库都要打开、关闭物理连接,系统性能严重受损。
解决方案:数据库连接池(Connection Pool),在系统初始化运行时,主动建立足够多的连接,组成一个池,每次
应用程序请求数据连接时,无需重新打开连接,而是从池中取出已有的连接,使用完后,不需要关闭,而是归还。
连接池中连接的使用和释放的原则:
应用启动时,会创建初始化数目的连接,当申请无连接或者达到指定的最小连接数时,按照增量参数值取创建新的连接
为了确保连接池中最小的连接数的策略:
动态检查:定时检查连接池,一旦发现数量小于最小连接,则补充相应的新连接,保证连接池正常运转。
静态检查:空闲连接不足时,系统才能检测到是否达到最小连接数,按需进行分配,用过归还,空闲超时就进行释放。
Apache DBCP连接池
DBCP连接池:数据库连接池,Apache的一个Java连接池的开源项目,同时也是Tomcat使用的连接池组件
连接池是创建和管理连接的缓冲技术,将连接准备好,能够被任何需要的应用使用。
需要两个jar包
commons-dbcp-1.4.jar 连接池实现
commons-pool-1.2.jar 连接池实现依赖的库
通过DataSource获取连接
1)通过属性配置文件获取连接池参数
2)加载参数,获得连接
参数:
初始连接数、最大连接数、最小连接数、最大空闲数、最小空闲数、
每次增加的连接数
3.事务
数据库中保证交易可靠机制,JDBC支持数据库中事务概念,在JDBC中事务默认自动提交
事务特性:
原子性:事务必须是原子工作单位,对于数据修改,要么全部成功,要么全部失败
一致性:事务在完成时,必须全部数据都保持一致状态
隔离性:由并发事务操作的修改必须与其他事务操作的修改隔离
持久性:事务完成之后,它对于系统的影响是永久的
事务是数据库的概念,JDBC是支持事务的,本质还是在数据库中实现的
JDBC事务提供的API(重点)
//获取事务默认的提交方式,默认是自动提交(值为true)
Connection.getAutoCommit();
//设置事务的提交方式,参数true表示自动提交,false表示不自动提交
Connection.setAutoCommit();
//事务提交
Connection.commit();
//事务回滚
Connection.rollback();
create table account( id char(2), money double(7,2) ); insert into account values('A',1000); insert into account values('B',2000); update account set money=money-500 where id=''; update account set money=1000 where id='A'; update account set money=2000 where id='B';
4.批处理
批处理:发送到数据库,作为一个单元执行的一组语句
批处理好处:降低应用程序和数据库之间的网络应用
相比单个SQL语句的处理,批处理效率高
更为有效
批处理API:
addBatch(String sql)
Statement中的方法,可以将多条SQL语句添加到Statement对象的SQL语句列表中
addBatch()
PreparedStatement中的方法,可以将多条SQL语句添加到PreparedStatement对象的SQL语句列表中
executeBatch()
把Statement或者PreparedStatement对象语句列表中全部SQL语句发送到数据库进行批处理
clearBatch()
清空之前的SQL语句列表
注意:
如果对象中的SQL列表包含过多的待处理语句,可能会产生内存溢出问题。
建议及时处理SQL语句列表
create table student( id int(4) primary key, name varchar(10) not null );
5.返回自动生成的主键值
Oracle通过序列对象进行主键自增长
MySQL是支持主键自增长
dept_xi
emp_xi
//给员工表deptno添加外键约束
alter table emp_xi add foreign key (deptno) references dept_xi(deptno);
操作:关联数据的插入
插入部门表的同时,往部门表中插入一个员工。主表/从表关联关系,插入数据时保证数据的完整性
如果单表操作,不需要返回插入的主键值
//不推荐,需要跟数据库进行多次交互
insert into dept_xi(dname,location) values('研发部','南京'); select deptno from dept_xi where dname='研发部'; insert into emp_xi(ename,deptno) values('张三',查询出来的部门号);
//推荐
利用PreparedStatement的getGeneratedKeys方法获取自增长类型的数据,性能良好,只有一次SQL交互
ps=con.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS); ps=con.prepareStatement(sql,Statement.1); ps.executeUpdate(); rs=ps.getGeneratedKeys(); rs.next();
//返回部门表插入数据对应的主键值
int deptno=rs.getInt(1);
//添加一个部门信息,同时往部门里添加一个员工
void addDeptAndEmp(Dept dept,Emp emp);
6.分页查询
JDBC实现Oracle的分页查询:利用rownum(伪列),传入SQL语句,以获得分页结果集
select * from(select empno,ename,rownum rn from emp_xi) where rn between ? and ?
//计算公式
page:第几页
pageSize:表示每页的记录
1页 1-5
2 6-10
3 11-15
int begin=(page-1)*pageSize+1; int end=page*pageSize;
//执行
ps=con.prepareStatement(sql); ps.setInt(1,begin); ps.setInt(2,end); ps.executeUpdate(); JDBC 实现MySQL的分页查询 select*from emp_xi limit begin,pageSize; select*from emp_xi limit ?,?; 1页 0-4 limit 0,5 2 5-9 limit 5,5 3 10-14 limit 10,5 int begin=(page-1)*pageSize; //开始是从0开始 int end=page*pageSize-1;
//执行
ps=con.prepareStatement(sql); ps.setInt(1,begin); ps.setInt(2,pageSize); ps.executeUpdate();
两种分页策略:
1)每次向数据库请求一页数据量,内存压力小,适合大数据量的表
2)一次性把数据全部查询出来放在缓存中,根据用户看的页数和每页记录数计算,把对应的数据显示出来