数据库的概念:
存储数据的仓库
安装MySql数据库
按照文档安装(2个路径记住,卸载要把路径里面的东西删除干净,把服务中的MySql的自动改成手动)
启动,关闭及登录MySql
net start mysql
net stop mysql
mysql -u用户名 -p密码
SQL语句介绍:
结构化查询语言简称SQL,是关系型数据库管理系统都需要遵守的规范。不同的数据库生产厂商都支持SQL语句,但都有特色的内容;
SQL语句分类:
数据定义语言:简称DDL,关键字:create,alter,drop等
@@数据操作语言:简称DML,关键字:insert,delete,update等
数据控制语言:简称DCL,用于定义权限,安全级别,及创作用户
@@数据查询语言:简称DQL,关键字:select,from,where等
使用SQL语句操作数据库
创建:
create database 数据库名称;
删除:
drop database 数据库名称
使用数据库:
use database
使用SQL语句操作表结构
create table 表名(
字段1 数据类型[长度][约束],([]的意思是可以没有,但是写的时候还是要写()的,还有逗号(,)千万不要忘记)
...
字段1 数据类型[长度][约束](最后一定不能有逗号)
); (注意括号和分号)
drop table 表名;
alter table 表名 change(修改类名和类型长度和约束)/modify(修改类型长度和约束)/add(增加一列) [change旧字段名] 新字段名 数据类型 约束;
使用SQL语句进行数据的添加修改和删除操作
insert into 表名(字段...) values(字段值...);
insert into 表名 values (值全部给出,包括主键);
update 表名 set 字段=字段值,... [where 字段=字段值]
delete form 表名 where 条件;
truncate table 表名;(会删除表中所有的数据,和清空主键自增,如果再添加数据,主键从新开始)
使用SQL语句添加约束
主键约束
唯一约束
非空约束
使用SQL语句查询数据:
select *|字段名 from表名
select distinct 字段名 from 表名(过滤重复字段,distinct后面只能过滤一个字段)
使用SQL语句进行条件查询:
select *|字段名 from 表名 where 条件
使用SQL语句进行排序
order by [asc升序][desc降序]需要写在末尾(不写默认的是asc升序)
使用聚合函数:对某一列数据进行查询,结果返回一个单一的值,会忽略null值
sum(求和)不是数值类型返回0,count(统计指定列不为null的记录行数),max(最大),min(最小),avg(平均值)不是数值类型返回0;
select count(*|字段) |sum(字段)|max(字段)|min(字段)|avg(字段) from 表名;
使用SQL语句进行分组查询:
select 被分组的字段... from 表名 [where 条件] group by 被分组的字段[having 条件]
where:分组之前进行条件过滤
having:分组之后,可以再次进行条件过滤
例子:
select pname,sum(price) from 表名 where price>1000 group by pname;
(查询pname和先过滤price>1000,再以pname进行分组,然后进行price的求和)
select pname,sum(price) from 表名 group by pname having sum(price)>1000;
(查询pname和先以pname进行分组,分组后过滤掉求和后的>1000的值)
分页查询:
关键字:limit
select * from 表名 limit m,n
m:每页的开始行数(可变的)
n:每页显示的个数(固定的)
数据库中的行开始索引是0,列开始索引是1
多表之间的关系及建表原则:
1:1 可以合成一张表
1:多 :多种使用1中的主键作为外键
多:多:有一张中间表,包含俩个表的主键作为外键
外键约束:保证数据的准确,完整性
格式:alter table 表名 add [constraint 外键名] foreign key(外键) references 主表(主键);
多表查询::::::
1,交叉查询:很少用,有错误的数据
格式:
select * from 表A,表B;
2,内连接:使用关键字[inner] jion on,添加一个外键约束的条件
a.隐式内连接:不使用关键字 [inner] jion on
格式:
select * from 表A,表B where 表A.主键=表B.外键;
b.显示内连接:使用关键字 [inner] jion on
格式:
select * from 表A [inner] jion 表B on 表A.主键=表B.外键;
3,外连接:使用关键字 left|right [outer] jion on
a.左外连接:以左边的表为主,左边有的数据,右边没有使用null代替
格式:
select * from 表A left [outer] jion 表B on 表A.主键=表B.外键;
b.右外连接:以右边的表为主,右边没有的数据,左边也不能有
格式:
select * from 表A right [outer] jion 表B on 表A.主键=表B.外键;
4,子查询:一条SQL语句嵌套另外一条SQL语句
a.一条SQL语句使用另外一条SQL语句的结果做为查询的条件
select * from 表B where 字段=(select 字段 from 表A [where 条件]);
b.一条SQL语句使用另一条SQL语句的结果做外另一张表,就相当于隐式内连接
select * from 表B,(select * from 表A [where 条件])另一张表 where 表A.主键=表B.外键;
原生JDBC:
使用Java程序根据sun公司提供的标准API进行操作数据库,对数据库进行增删改查,它由一组用Java语言编写的接口和类组成。
JDBC使用步骤:
1,注册驱动
告知jvm我们使用的是哪个数据库厂商提供的驱动(mysql驱动,oracle驱动...)
Class.forName("com.mysql.jdbc.Driver");
2,获取数据库连接对象
mysql数据库,采用的是TCP服务器,我们的使用客户端经过三次握手,和数据库之间建立连接通路(IO流对象)
static Connection getConnection(String url, String user, String password) 试图建立到给定数据库 URL 的连接
参数:
String ulr:mysql服务器的地址,固定格式
jdbc:mysql://ip地址:端口号/数据库名称
jdbc:mysql://127.0.0.1:3306/day04
jdbc:mysql://localhost:3306/day04
返回值:connection
返回的是connection接口的实现类
3,获取执行sql语句的执行者对象
用来执行sql语句
使用Connection接口中的方法
Statement createStatement() 创建一个 Statement 对象来将 SQL 语句发送到数据库。
4,使用执行者对象执行sql语句,获取执行结果
使用Statement接口中提供的方法
int executeUpdate(String sql) 执行给定 SQL 语句,该语句可能为 INSERT、UPDATE 或 DELETE 语句
int:执行增删改,影响数据库的有效行数(affected受影响的)
ResultSet:执行查询语句,会查询出多条数据,放入结果集中
5,处理结果集
使用Statement对象中的方法executeUpdate执行查询语句,返回影响数据库的有效行数
使用Statement对象中的方法executeQuery执行查询语句,返回单个 ResultSet 对象
ResultSet是一个接口,executeQuery返回是executeQuery接口的实现类,由mysql驱动提供,不需要关注
只需要知道使用ResultSet接口来接收这个实现类对象(多态)
6,释放资源
注意:1,2,3,6是固定步骤,45根据执行的增删改查不同进行不同的处理
描述sql注入攻击的原理和解决方案
or 1=1
使用PreparedStatement可以屏蔽sql中的or 1=1
能够通过PreparedStatement完成CURD代码
PreparedStatement pst = conn.prepareStatement(sql);
拼接sql语句,可以使用?占位符来代表实际参数
String sql = "SELECT * FROM users WHERE username=? AND PASSWORD=?"
void setObject(int parameterIndex, Object x) 使用给定对象设置指定参数的值
参数:
int parameterIndex:要设置的第几个?占位符;1,2,3,4
Object x:?占位符实际使用的值
用使用PreparedStatement中的方法executeQuery执行查询的sql语句
int row = pst.executeUpdate();
ResultSet rs = pst.executeQuery();
创建数据库表Users的javaBean
数据库的Users表-->Users类
表中的列-->类中的成员变量
表中的行-->Users对象
包含:
1.私有的成员变量
2.公共的get/set方法
3.空参数构造方法
4.toString方法
5.实现序列化接口:
需要实现Serializable
Serializable叫标记型接口
Person类实现了(标记)Serializable接口,就可以序列化和反序列化了
public class Category implements Serializable {
private static final long serialVersionUID = -5763231917211692531L;
能够理解连接池的原理
池中有多个连接,使用连接时可以从池中获取,使用完毕归还到连接池
能够使用DBCP连接池
工具类
成员位置创建DataSource实现类对象
private static BasicDataSource dataSource = new BasicDataSource()
private static DataSource dataSource(properties文件)
使用静态代码块设置4大连接信息
使用配置文件设置4大连接信息:静态代码块中:
properties集合读取文件,
InputStream is = DBCPUtilsConfig(工具类名).class.getClassLoader().getResourceAsStream("dbcpconfig.properties")
使用类加载器中提高的流对象,可以扫描src|bin目录下的文件
b.使用连接池工厂类BasicDataSourceFactory,创建BasicDataSource对象
dataSource = BasicDataSourceFactory.createDataSource(prop);
能够使用C3P0连接池
工具类
成员位置创建DataSource实现类对象
private static ComboPooledDataSource dataSource = new ComboPooledDataSource()
使用静态代码块设置4大连接信息
使用xml设置4大连接信息(自动解析读取)
注意:同时存在静态代码块赋值和xml,优先使用静态代码块
能够理解DBUtils工具类
可以简化JDBC操作
能够应用QueryRunner类
创建对象
QueryRunner()
调用方法update(conn) query(conn)
QueryRunner(DataSource)
调用方法update() query()
能够应用ResultSetHandler接口
9个3个重点
BeanHandler
BeanHandler内部会使用反射技术,根据传递Category.class,创建一个Category对象,使用setXXX方法给对象的属性赋值
会把结果集中的第一行数据,存储到javabean
query的返回值
返回的就是javabean对象;传递Category.class返回的Category对象
BeanListhandler
构造方法:
BeanListHandler(Class<T> type) :需要传递JavaBean的class文件对象;传递Category.class
内部会通过反射技术创建javabean对象并赋值
会把多行结果存储到多个javabean中,多个javabean存储到一个List集合中
ScalarHandler
ScalarHandler用于sql语句查询的结果是一个单一的值
query的返回值:
返回的类型多种多样,所以使用Object类型
理解事务的概念:
l事务指的是逻辑上的一组操作(多条sql语句在一个Connection中),组成这组操作的各个单元要么全都成功,要么全都失败.
事务作用:保证在一个事务中多次操作要么全都成功,要么全都失败 一组:指的是只能使用一个Connection
理解脏读,不可重复读,幻读的概念及解决办法
能够在MySQL中使用事务
能够在转账功能中使用DBUtils开发包完成事务控制
能够使用DBUtils并通过ThreadLocal绑定Connection的方式控制事务
java.lang.ThreadLocal<T>:该类提供了线程局部 (thread-local) 变量。
ThreadLocal这个类内部包含了一个Map集合
Map<当前线程,Object> map = new HashMap<当前线程,Object>();
注意:
如果没有开启新的线程,当前线程就是main线程
ThreadLocal成员方法:
void set(T value) 将此线程局部变量的当前线程副本中的值设置为指定值
就相当于调用了Map集合中的put方法,往集合中添加元素
key:当前线程(Thread.currentThread())
value:存储任意的值,(ThreadLocal的构造方法定义什么类型的泛型,就存储什么类型的值)
T get() 返回此线程局部变量的当前线程副本中的值。
就相当于调用了Map集合中get(key)方法,根据key获取value
key使用的默认就是当前线程
void remove() 移除此线程局部变量当前线程的值。
就相当于调用了Map集合中的remove(key),根据key,删除键值对
key使用的默认就是当前线程
线程局部 (thread-local) 变量:哪个线程存储的值,只有哪个线程能取出来,其它线程不能操作(看不到)
创建ConnectionManager连接管理的工具类
抽取Service中的获取数据库连接和事务
1.在成员位置创建一个ThreadLocal对象用于存储Connection
2.定义一个获取Connection的静态方法
3.定义一个开启事务的静态方法
4.定义一个提交事务的静态方法
5.定义一个回滚事务的静态方法
6.定义一个释放资源的静态方法
2:例子
定义一个获取Connection的静态方法
public static Connection getConnection(){
Connection conn = tl.get();//根据当前线程获取conn
if(conn==null){
//从C3P0连接池中获取一个连接
conn = C3P0UtilsConfig.getConnection();
//使用当前线程作为key,conn作为值存储到ThreadLocal中
tl.set(conn);
}
return conn;
}