第一章
命令行工具
mysqladmin:MySQL服务器管理工具
mysql:MySQL客服端链接工具
mysqldump 演示链接到服务器host=127.0.0.1,用户名为root,密码为空
mysql.exe -h 127.0.0.1 -u root
>use test;
>select*from example;
>quit;
注:初始状态下,root密码为空 C/S架构(Client/Server)
一台主机运行MySQL
多台客服机同时链接. 第二章 2.1创建数据库
数据库 Database,就是存储数据的仓库
MySQL自带4个数据库
test是测试用.
其余的三个是系统库 右键创建example
右键example 更多数据库操作,删除数据库 1.在MySQL服务器里,可以创建多个数据库
2.数据库的命名规则:
-用有意义的名字.
-多个单词用下划线连接,如company_project
-全部使用小写字母.
3.不要操作MySQL自带的系统库. 2.2 创建表
-创建数据库rh_school,用于存储学校内的数据.
-创建表rh_student,用于存储学生信息
学生信息:
列名 数据类型 长度
id int
name varchar 32
phone varchar 16
birthday date 向表中添加数据.
对rh_student点右键打开表.
添加数据,保存. 改完后,点保存(离开该行时会自动保存.)
C/S架构
此时数据已经存储到数据库里
用户从其他电脑也可以用SQLyog登录访问MySQL 学习了如何创建一张表,向表里添加多行数据,了解三种数据类型. 2.3 数据类型
整数 int 更多tinyint,smallint,int,bigint.
字符串 varchar 更多 char,varchar
浮点型 double double,float
日期时间 datetime 更多date,time,datetime,timestamp.
大块数据 text/blob 更多tinytext,text,mediumtext,longtext,blob... 整数类型 tinyint(1字节),smallint(2字节),mediumint(3字节),int(4字节),bigint(8字节).
//如果不确定,就用int,一般够大了. 浮点类型:用于保存小数
double(8字节)
float(4字节)
//如果不确定,就用double类型. 字符串类型.
char:固定长宽字符串
varchar:可变长度字符串
注:1.必须指定最大长度
2.如果你不确定,就用varchar
3.最大的字符串适合用varchar?10k以下吧 日期类型.
datetime:日期时间 具体格式:2018-3-10 11:09:09
date:日期
time:时间
timestamp:时间戳(自1970-01-01 00:00:00)
year:年份
不确定使用datetime. 大块数据.
BLOB(binary large object),二进制大对象
比如,你想把一个图片文件做为一列存储到数据里(不建议)
text 存储大段文本数据.
blob 存储大段字节数据
text(65k),mediumtext(16M),longtext(4G) 2.4 列的属性
列名的设置:可以是中文,但通常是英文
-不要使用SQL里的关键字 database table
-使用有意义的单词 简写
-第一个单词小写(与java兼容,减少麻烦)
如:realName,fileSize,storePath 列的属性,使用2.3推荐的. 长度length
对于varchar/text字段,需设置最大长度
-不区分中英文,按字符数统计.
-太长的字符串,不适合varchar存储.
varchar(512)和varchar(1024)实质没有差别,按实际大小存储.
对于其他类型,不需要设置长度(意义不大)
例如,int(4)表示最小显示宽度为4,不足时凑空格或0(需勾选ZeroFill属性) 列的属性:非空?
空值null:指这一列的值尚未设置
当一列设置为非空时,表示该列必须设置.
String str=null; //空值NULL
String str=""; //空字符串. 默认值
若某列没有设置值,固定赋值. 2.5 主键和自增
主键 Primary Key
主键,即是唯一标识.
例如:在student表中,可以设id为主键,因为id可以唯一标识一行记录
在订单表中,可以将订单id设为主键,订单id可以唯一标识一个订单. 主键设计遵循以下原则:
可以唯一标识一条数据.
通常为整形或字符串型(短字符串)
一个表最多只要一个主键
主键可以是第一列,也可以是最后一列,数据库里的列的顺序是不重要的(顺序无关)
建议所有的表都设置主键(非必须) 1.name字段可以做为student表的主键吗
2.为什么应该用比较短的字段做为主键,长字符串行吗
3.联合主键.
使用多字段合在一起做为主键,id+name,但还是一个主键. 主键的作用
主键唯一标识一行记录
MySQL会把主键单独拿出了,存为一个索引,排序后存储(方便后续查找)
显然,整数主键的查找速度更快. 自增
当以整形字段做为主键时,可以同时设置为自增
所谓自增,即是插入记录时,由MySQL来生成ID,保证ID是自增(每次+1) 自增的起点:
新建的表,默认为1开始.
或表中有数据,从上一个最大值开始.
过号作废,不重复(删除10以后,下一个auto不会是10,是11)
可以指定起点.
改变表高级自动增量. 3.1 SQL
SQL Structured Query Language
SQL语句:客户端用来操作数据库的语句. 在SQLyog里演示:
CREATE DATABASE xxx_example;
DROP DATABASE xxx_example;
作用:创建/删除数据库"xxx_example" 客户端和服务器的交互
用户名/密码
SQLyog电脑A----------->MySQL电脑B
<-----------
登录成功 CREATE DATABASE xxx_example;
----------->
<-----------
操作成功 SQLyog历史记录
实际上每个SQLyog里的操作,都是生成了一个SQL语句发给服务器
在询问窗口练习SQL语句,效率最高.
SELECT * FROM rh_school.`rh_student` 3.2 SQL创建数据库
CREATE DATABASE xx_sample 创建
关键词不区分大小写,CREATE/create均可
名称以反引号引起来. //暂时不能添加''添加''无法正确创建. DROP DATABASE xxx_example;删除 UES xxx_sample;
切换数据库. 数据库命名规则
-用有意义的名字.
-多个单词用下划线连接,如company_project
-全部使用小写字母.不要使用空格和特殊字符.
-不要使用系统关键词. 3.3 SQL创建表
CREATE TABLE命令可以创建表
CREATE TABLE `student`(
`id`int(11)NOT NULL,
`name`varchar(64)NOT NULL,
`phone`varchar(16)DEFAULT'1380000',
`birthday`date DEFAULT NULL,
PRIMARY KEY(`id`)
);
数据是使用单引号,前面的列名是反引号.``'' 删除表
DROP TABLE IF EXISTS `student`; 如果存在再删除,IF EXISTS. ALTER TABLE //修改表不太常用. 3.4 SQL插入数据
创建准备用的表.
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`(
`id`INT(11)NOT NULL COMMENT '学号',
`name`VARCHAR(64)NOT NULL COMMENT'姓名',
`phone`VARCHAR(16)DEFAULT '13090'COMMENT '手机号',
`birthday`DATE DEFAULT NULL COMMENT'生日',
PRIMARY KEY (`id`) ); 插入数据
INSERT INTO命令可以插入数据.
语法:
INSERT INTO 表名
(列1,列2....)
VALUES
() INSERT INTO `rh_sample`.`student`
(id,`name`,phone,birthday)
VALUES
(20180001,'xx','130313131','1982-1-1') 列名指定时不需要按照顺序.
但是列名需要和值values一一对应. 简化写法1:
如果按照顺序将所有列赋值,可以不写列名
INSERT INTO`rh_sample`.`student`
VALUES('20180001','xx','123123','1991-12-21') 简写2:
如果名字其得比较规范,那么数据库名,表名,列名都可以省略引号
INSERT INTO student
VALUES('20180001','xx','123123','1991-12-21') 简写3:
对于整数或者小数值,可以省略单引号,对于其他类型,必须加单引号.
INSERT INTO student
VALUES(20180001,'xx','123123','1991-12-21') 在一条SQL里插入多行数据.
INSERT INTO `rh_sample`.`student`
(id,`name`,phone,birthday)
values
(20180001,'xx','130313131','1982-1-1'),
(20180002,'xx1','130313131','1982-1-1'),
(20180003,'xx2','130313131','1982-1-1'),
(20180004,'xx3','130313131','1982-1-1') 只列出部分字段. 3.5 查询SQL数据 最常用最重要.
sql script sql脚本
SELECT * FROM student
SELECT * FROM student WHERE id='20180004'
指定过滤条件
使用WHERE字句可以指定过滤条件,不符合条件的行将被删除不显示.
WHERE id='20180001'
WHERE id <>'20180001'; //不等于
WHERE phone IS NULL; //手机号为空
WHERE birthday >'2011-1-1'; //11年以后 多个条件可以用AND OR
例如:
WHERE id>'20180002'AND id<'20180005'
WHERE id>'20180002'OR id<'20180005' 还可以小括号联立多个条件
xxx AND yyy AND(zzz OR www) 指定列
在查询时,可以只返回部分列,
select * from student; //返回全部列 select name,birthday from student where id<20180003; //返回姓名,生日. 3.6 SQL数据更新 UPDATE
UPDATE 表名SET 列名='value' WHERE 过滤条件
示例:
UPDATE student SET phone='13800100' WHERE id='20180001' 示例2:
UPDATE student SET phone=NULL WHERE id>='20180001'AND id<='20180003'
可见,一条UPDATE 语句可以一次性修改所有符合条件的行. 示例3:
UPDATE student SET phone='130000',birthday='1991-1-1'WHERE id='20180001'
可见一条UPDATE 语句可以修改多个列. 示例4:
UPDATE article SET numView=numView+8 WHERE id='1000'
可见 SET语句里可以比较特殊的写法 (在原数字上加8) 3.7删除数据
删除一个表里的所有数据(清空/截断表)
TRUNCATE TABLE article;
注意:自增基数也被重置.
删除指定行
用DELETE 命令删除指定行,
DELETE FROM 表名 WHERE 过滤条件
注意:如果不添加where限制,会删除所有行. 增,删,查,改操作中select语句是重点.
在数据库领域,通常把这4种操作简称为CRUD
增加(CREATE) 读取(RETRIEVE) 更新(UPDATE) 删除(DELETE) 4.1 结果集ResultSet
查询结果集ResultSet
使用SELECT语句查询时,MySQL返回多行,称为结果集 多行数据
SQLtog<----------------- MySQL
客户端------------------> 服务器
Select id,name FROM student 返回指定列
返回所有列
SELECT * FROM student //*表示全部
返回部分列
SELECT id,name FROM student 更改列标签Column Label(或称列名)
可以手工指定结果集的列名
SELECT id AS`学号`,`name`AS`姓名`FROM student; 排序使用ORDER BY字句,可以让结果排序
SELECT * FROM student WHERE sex='1' ORDER BY id ASC,birthday DESC
其中,ASC表示升序,DESC表示降序. 4.2 高级查询
范围查询 使用IN可以指定一个范围
SELECT * FROM student WHERE id IN('20180001','20180003','20180005');
使用IN指定一个列表,凡在此列表中的则符合条件,
(注:NOT IN 表示不在列表里.) 空值查询
示例:SELECT * FROM student WHERE phone IS NULL
SELECT * FROM student WHERE phone IS NOT NULL 相似查询
对于字符串字段,可以使用精准查询或者相似查询,
精准查询:where name ='张良'
相似查询
WHERE name LIKE'%良%'
WHERE name LIKE'张%'
WHERE name LIKE'张%良'
注:对于Oracle,SQL Server统配符可能不是% 使用函数
对于字符串段,可以使用精确查询或相似查询
比如:
SELECT * FROM student WHERE YEAR(birthday)>=1980 AND YEAR(birthday)<1990;
其中YEAR(birthday),就是MySQL内嵌的函数,可以求日期字段的年份.
MySQL有几十个小函数,可以用于对字段或结果集进行简单处理,
比如: SELECT MAX(id) FROM student //取集合里的最大ID
注:Oracle,MySQL,SQL Server各自支持的函数不一样,不通用. 5.1 表的设计
介绍基础技术.
命名规范:
数据库名:全小写,用下划线链接
推荐为company_project
表名:全小写,用下划线连接
user_role student_exam
列名:第一个词小写,后面首字母大写
displayName , numView 表的规模
一个数据库里,通常有很多表,但每张表的特点是不一样的.
表的规模:该表的最终存储规模
有的表只能存储几百条记录,而有的达到几万条
结论:只有存储规模较大的表才值得精打细算. 表的访问
每个表访问频率不同
有的很少被访问,有的访问频繁.
例如:
商品表,可能会经常用于查询
系统日志表记录了系统事件,很少被访问.
结论:当一个表经常被访问时,要精心设计. 合适的数据类型
tinyint 比 int可能有的好处
-节省存储空间(如果表的规模太小,则忽略)
-加快传输效率(如果MySQL同机部署,则忽略)
-加快数据备份的速度(如果数据备份不常发生,则忽略) 5.2 主键和索引
主键:快速定位,保证唯一性
设计时注意两点:
1.每个表都应该设立主键
2.主键字段一般用整数或短字符串 索引Index
只能从前往后遍历,为了加快日期查询速度,可以建立`生日`索引
(1).索引里存储生日和行指针
(2).索引里按顺序存储. 添加索引
ALTER TABLE `af_school`.`student` ADD INDEX (`birthday`); 在建立索引时,可以额外指定类型
-普通索引:默认索引类型
-唯一索引 Unique:索引里的值不允许重复 ALTER TABLE `af_school`.`student` ADD UNIQUE INDEX (`phone`);
-主索引 Primary:主键也是一种索引
-全文索引 FullText: 为长文本建立的索引 在执行增删改操作时,除了要修改主表,还要同步修改索引,因此索引不应无节制的添加. 5.3表的关联
已经有一张表student,存储学生信息
现在添加一张表,表示每个学生所考试成绩
在逻辑上,表exam和student有关联性,
exam.id和student.id一一对应
所有,exam表中不需要存储name等字段. 关联查询
SELECT`name`,`chinese`,`english`,`math`,`phone` FROM exam,student WHERE exam.`id`=student.`id` 两个关联表所有列全部查询 SELECT * FROM exam,student WHERE exam.`id`=student.`id` //id会输出2次. SELECT b.`name`,a.`chinese`,a.`english`,a.`math`,`phone`
FROM exam a,student b
WHERE a.`id`=b.`id`
设置exam为a,student为b.方便查询. 5.4 内连接
多表关联查询,有以下几种方式:
-内连接 INNER JOIN
-外连接
左外连接LEFT OUTER JOIN
有外连接RIGHT OUTER JOIN
-全连接,交叉连接... 内连接
示例:
SELECT *
FROM student a INNER JOIN exam b
ON a.id =b.id
WHERE a.sex=0
其中,ON表示连接条件. 内连接INNER JOIN 内连接等效于5.3的WHERE查询
SELECT * FROM student a,exam b WHERE a.id=b.id AND a.sex=0; SELECT a.`name`,b. *
FROM student a INNER JOIN `leave_event` b
ON a.`id`=b.`stuId`; 性能问题
1.谁JOIN谁有什么区别.
a JOIN b
b JOIN a
-不用管,MySQL会自己进行优化. (驱动表和被驱动表,小表驱动大表)
2.连接查询比单表查询要慢. 5.5 外连接.
OUTER JOIN
SELECT *
FROM student a LEFT OUTER JOIN exam b
ON a.`id`=b.`id`;
左外连接表示以左边表为基准,右边没有的项补为null
如果左边少项,右边多,则输出右表多的项不输出.
5.6    外键
外键 FOREIGN KEY ,是一种约束条件.保证逻辑上的完整性.
例如:
有student学生表 学生信息,
有exam 表示学生成绩,以学号字段进行关联
现在,在学生表里删除一条学生的记录,可以吗.
显然不管外部约束,盲目删除student表的数据,会导致整个系统数据不完整. 修改exam表,添加外键约束.
然后从student删除一条数据.
外键作为约束条件,用于维护数据的完整性. 删除选项 cascade 级联设置,在student表中删除一项,在exam自动删除.
//外键不能同时多表关联一个主表的同一字段. 6.1 用户与授权
用户与密码
默认的,MySQL自带root用户,而且密码为空 系统表mysql.user
记录了用户名密码.
host:允许从那台主机登录(客户端IP限制)
User:用户名
Password:密码
权限:select,insert,create.
注:这个表时联合主键host+user 1 设置用户授权
GRANT命令的语法:
GRANT
ALL PRIVILEGES
ON 库名.表名
TO '用户名' @ 'IP地址'
IDENTIFIED BY '密码'
WITH GRANT OPTION ; 其中,
all privileges 表示授予所有权限,其实可以把各项权限单列出来
on 指定该用户可以访问的数据库/表
to 指定用户名、和客户端IP范围
identified by 指定密码
后面还可以分别指定增删改查权限 FLUSH PRIVILEGES; /* 运行此命令则立即生效,不需要重启服务器 */ 2 修改密码
UPDATE mysql.user
SET `password`=PASSWORD('a1b2c3')
WHERE `Host`='127.0.0.1' AND `User`='root' 其中,PASSWORD是一个MySQL的函数,用于把字符串加密成密码字符串 3 允许 root远程访问
运行以下两行,即允许客户端从任意IP来访问服务器
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'a1b2c3' WITH GRANT OPTION;
FLUSH PRIVILEGES; 其中,'root'@'%' 是设置这两个字段: Host='%' User='root' host%表示可以从任意IP地址访问. 其实也设置为一个子网范围,如 'root'@'192.168.8.%' 则允许root从IP地址为 192.168.8.%的子网来访问。 4 立即生效
所有的用户、密码、授权操作不会立即生效,而是在重启MySQL服务器后才会生效。 如果想立即生效,则运行
FLUSH PRIVILEGES; 注意事项
1.数据库应该设置一个密码.
2.用户指访问数据库的用户,并非业务系统里的用户.
3.MySQL一般不开放远程访问,一般限制为内网访问,否则容易受攻击
4.所有,一般开放'root'@'机户内网网段'就够了. 6.2 允许远程访问
指从另外一台电脑登录访问MySQL服务器
服务器配置
1.MySQL里,允许'root'@'%'访问
注意:先不要设为'root'@'192.168.1.%' 2.关闭防火墙
注:MySQL的端口为3306,但为了简单起见,先统一关闭. 6.3 服务器配置
修改my.ini里的配置项,
一般不需要修改. 6.4 备份与还原
设想,如果有一天,MySQL主机发生了物理损坏.如果数据丢失怎么办
-定期备份
-如果出现灾害,重建服务器,并导入数据 MySQL自带的两个工具
mysqldump.exe 用于备份
mysql.exe 用于还原 1.切换到mysql的bin目录
cd /d d:\mysql5\bin 2.用mysqldump.exe导出
mysqldump.exe -hlocalhost -uroot -pa1b2c3 --databases af_school >d:\backup.sql
其中,主机localhost 用户名root 密码a1b2c3 数据库af_school 导出到d:\backup.sql 3.导入SQL
mysql.exe -hlocalhost -uroot -pa1b2c3 <d:\backup.sql 7.1 Java数据库连接(JDBC)
JDBC java database connectivity
使用java技术进行数据库连接的技术
JDBC API:java.sql.*
里面规定了各种数据库服务器操作的标准接口.
(另外需要一个相应的驱动jar包) public class Test
{ public static void testConnect() throws Exception
{
// 注册MySQL驱动 (可以省略这一步)
Class.forName("com.mysql.jdbc.Driver"); // 连接MySQL服务器
String username= "cqcrh";
String password = "cqkill";
String connectionUrl = "jdbc:mysql://127.0.0.1:3306/af_school?useUnicode=true&characterEncoding=UTF-8"; Connection conn = DriverManager.getConnection(connectionUrl, username, password);
System.out.println("连接成功!"); conn.close();
System.out.println("关闭连接!");
} public static void main(String[] args)
{
try
{
testConnect();
} catch (Exception e)
{ e.printStackTrace();
}
} } 1.java.sql.*下规定了标准接口,而MySQL驱动里则是各个接口的实现.
2.MySQL驱动的内部封装了与服务器的交互协议
3.Class.forName("com.mysql.jdbc.Driver");
这一行用于显示注册MySQL驱动,但是可以省略,后面专门讲解. 7.2 JDBC查询数据.
连接见7.1
//数据库查询,Statement语句 ResultSet结果集
Statement stmt = conn.createStatement();
ResultSet rs=stmt.executeQuery("SELECT * FROM student"); //如果有数据,rs.next()返回值为true
while(rs.next())
{
//输出行数据
System.out.println(rs.getInt("id")+ "\t"+rs.getString("name")+"\t"+rs.getString("phone")); } ResultSet里面存储了结果集,while只是遍历而已. 7.3 JDBC插入数据 String sql ="INSERT INTO student(`id`,`name`,`birthday`)"
+"VALUES('20180100','rhc','1999-4-19')";
System.out.println("SQL"+sql); Statement stmt =conn.createStatement();
stmt.execute(sql);
int count =stmt.getUpdateCount();
System.out.println("受影响的行为"+count); 当主键设为自增时.
1.插入数据时,不写该字段
2.执行时指定RETURN_GENERATED_KEYS
3.取出返回的自增主键.
String sql="INSERT INTO leave_event(`stuId`,`daysFrom`)"+"VALUES('20181234','2018-1-2')"; Statement stmt =conn.createStatement();
stmt.execute(sql,Statement.RETURN_GENERATED_KEYS); //statement.RETURN_GENERATED_KEYS 返回自增主键.
//取得自动生成的主键的值
ResultSet rs=stmt.getGeneratedKeys();
while(rs.next())
{
int id=rs.getInt(1);
System.out.println("产生的主键为"+id);
} delete和update用法相同,修改sql语句就行额. 7.4 SQL语句的构造
最常出错的地方就是SQL语句的构造.
在SQLyog里写可以.
可以写一个工具类来实现. 7.5 预处理查询
实现连接
//1.构造一个SQL,参数值用?号代替,称为占位符
String sql ="INSERT INTO student (id,name,birthday) VALUES(?,?,?)";
//2.创建PreparedStatement对象(于MySQL产生一次交互)
PreparedStatement ptmt = conn.prepareStatement(sql);
//3.设置参数值
ptmt.setInt(1, 20183001);
ptmt.setString(2,"星星");
ptmt.setString(3, "1991-12-1"); //4.执行查询
ptmt.execute(); 分为两步,第一步发送sql,第二步发送值.
预处理的优点.
使用预处理查询处理步骤:
-mySQL接收到预处理的SQL
-解析SQL请求
-服务器收到参数的值
-执行查询
-返回结果 在连续执行多个结构相同,参数不同的查询时,使用预处理技术有性能优势. String sql=....
PreparedStatement ptmt=...
while(...)
{
ptmt.set(1,..)
ptmt.set(2,...)
ptmt.execute();
}
在解析结构时只用执行一次.先传结构再传数据.
并不是所有的服务器都支持预处理技术. 8.1 结果集的分析.
结果集JDBC返回的一个结果集
包括2部分信息:
-多行数据
-描述信息,即元数据MetaData 从结果集里面,可以读取每一行数据
Result rs =stmt.executeQuery(sql);
while(rs.next())
{
}
*结果集里的数据都是字符串,都可以用getString来获取.
*可以按列标题,也可以按列序号,列序号从1开始,1,2,3... //前面连接数据库语句
//SQL语句数据库查询,Statement语句,ResultSet结果集
String sql="SELECT id AS 学号,name AS 姓名,birthday FROM student";
Statement stmt = conn.createStatement();
ResultSet rs =stmt.executeQuery(sql);
//设置id为学号,name为姓名.用getString只能获取学号,姓名,不能是id,name了.
//显示结果集数据
while(rs.next())
{
String id = rs.getString("学号");
String name =rs.getString("姓名");
String birthday =rs.getString("birthday");
System.out.println(id+"\t"+name+"\t"+birthday);
} 获取元数据
结果集的描述信息,即:有多个列,列名/列标题,列类型...
代码
//前面连接数据库语句
//SQL语句数据库查询,Statement语句,ResultSet结果集
String sql="SELECT id AS 学号,name AS 姓名,birthday FROM student";
Statement stmt = conn.createStatement();
ResultSet rs =stmt.executeQuery(sql); //显示元数据信息
ResultSetMetaData rsmd =rs.getMetaData();
int numColumns = rsmd.getColumnCount();
for(int i=1;i<=numColumns;i++) //序号1,2,3,4...
{
String name =rsmd.getColumnName(i); //原始列名
String lable =rsmd.getColumnLabel(i); //别名 AS
int type = rsmd.getColumnType(i); //类型,参数,java.sql.Types定义
String typeName =rsmd.getColumnTypeName(i); //类型名称 System.out.printf("第%d列:%s,%s,%s(%d) \n",i,name,lable,typeName,type);
} 8.2 POJO对象.
POJO, Plain Ordinary Java Object
简单Java对象
-属性
-构造方法
-Getter/Setter
示例:创建一个Student类,表示学生信息. 在数据库查询到结果后转换成POJO.
例如:从af_school_student表中查询结果,转成List<Student>对象...
public class AfSqlConnection
{
//
public String ip; // 服务器IP
public int port = 3306; // 服务器端口
public String catalog; // 数据库名 Catalog
public String username;
public String password; //
Connection conn; public AfSqlConnection(String ip, int port,
String catalog,
String username,
String password)
{
this.ip = ip;
this.port = port;
this.catalog = catalog;
this.username = username;
this.password = password;
} // 连接数据库
public void connect () throws Exception
{
// 示例 jdbc:mysql://127.0.0.1:3306/af_school?useUnicode=true&characterEncoding=UTF-8
String urlfmt = "jdbc:mysql://%s:%d/%s?useUnicode=true&characterEncoding=UTF-8";
String connectionUrl = String.format(urlfmt, ip, port, catalog); conn = DriverManager.getConnection(connectionUrl, username, password);
} // 关闭连接
public void close()
{
try {
conn.close();
}catch(Exception e) { }
} // 执行查询
public ResultSet executeQuery(String sql) throws Exception
{
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
return rs;
}
}
设计一个sqlConnection工具类,
使用工具类,实现添加POJO对象.
public class Test2
{ public static void testQuery() throws Exception
{
AfSqlConnection conn = new AfSqlConnection("127.0.0.1", 3306,
"af_school","root", "cqkill000"); conn.connect();
System.out.println("连接成功!"); /////////////////////////////////////////////// // 数据库查询, Statement语句 ResultSet结果集
String sql = "SELECT id , name ,sex, phone, birthday FROM student";
ResultSet rs = conn.executeQuery(sql); // POJO对象列表
List<Student> rows = new ArrayList<>();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // 显示结果集的数据
while(rs.next())
{
// 取出这一行记录
String id = rs.getString("id");
String name = rs.getString("name");
String sex = rs.getString("sex");
String phone = rs.getString("phone");
String birthday = rs.getString("birthday"); // 转成POJO对象
Student s = new Student();
s.setId( Integer.valueOf( id ));
s.setName( name );
if(phone!=null) s.setPhone(phone);
if(sex!=null)
{
s.setSex( sex.equals("1"));
}
if(birthday!=null)
{
s.setBirthday(sdf.parse(birthday) );
} rows.add(s);
} //////////////////////////////////////////////
conn.close();
System.out.println("关闭连接!");
for(int i=0;i<rows.size();i++)
{
Student s =rows.get(i);
System.out.println(s); //重写了Student的toString方法.
} } public static void main(String[] args)
{
try
{ testQuery(); } catch (Exception e) {
e.printStackTrace();
}
} } 8.3 POJO的自动映射 //重学. public static void testQuery() throws Exception
{
AfSqlConnection conn = new AfSqlConnection("127.0.0.1", 3306,
"af_school","root", "a1b2c3"); conn.connect();
System.out.println("连接成功!"); /////////////////////////////////////////////// // SQL查询并自动映射为POJO
String s1 = "SELECT id , name ,sex, phone, birthday FROM student";
List<Student> students = conn.executeQuery(s1, Student.class);
//.class方法属于java基础类,用于描述一个class对象. String s2 = "SELECT * FROM exam";
List<Exam> exams = conn.executeQuery(s2, Exam.class); //////////////////////////////////////////////
conn.close();
System.out.println("关闭连接!");
} 实现原理:相关源码AfSqlConnection,AfSqlReflect
1.从ResultSet里取得每列的label和value
2.根据label,得到POJO里的setter
例如:从`birthday`->setBirthday()
3.利用反射技术,调用setBirthday() POJO注意事项.
-属性使用包装类型,即大写的Integer ,Long,Boolean(以便应对数据库里的NULL)
-属性名应该与数据库名对应
-所有属性加上set get方法. 8.4 POJO的手动映射
POJO<-->table
自动映射:自动将列名和类的属性一一对应.
手动映射:通过额外的设置,描述POJO与table的对应关系.
通常有2种方法,XML,或者注解, POJO另外找方法学习. 9.1 MySQL连接数.
MySQL连接数:指客户端发起的网络连接数量.
查看最大连接数(my.ini中设置)
SHOW VARIABLES LIKE 'max_connections'
查看当前连接
SHOW STATUS LIKE 'Threads%' //连接数量
SHOW processlist //连接详情
SHOW full processlist JDBC connection
DriverManager.getConnection(connectionUrl, username, password);
//JDBC连接的方法 .colse //JDBC断开连接. 1创建Connection时,MySQL连接数+1
2关闭Connection时,连接数-1
jdbc驱动为我们创建的Connection对象对应了一个网络连接(socket连接) 思考:如果JDBC操作完不关闭连接,会如何. 9.2 连接池
有两种方式(短连接/长连接)
-每次创建一个连接,查询完毕后断开连接.
-只保持一个连接,每次都使用这个连接查询. 短连接方式
使用短连接方式,效率低
(连接耗时几百毫秒,响应速度慢.)
使用System.currentTimeMills()记录时间.
连接SQL服务器是一个重量级操作. 长连接方式
一个连接上,执行多个人次的操作.
(连接一直存在,用完了不关闭)
问题:同一时间只能满足一路查询,不能支持并发. 连接池 Connection Pool
连接池时一种常用的提高MySQL使用率的技术
设置思路:
-保持M个长连接
-当需要访问MySQL时,从中取了一个空闲的连接,用这个连接进行SQL操作
另外,内部会设置一个最大连接数限制,避免无限制开连接. C3P0连接池.
C3P0是一个第三方库,里面实现了连接池的设计策略
www.mchange.com/projects/c3p0 9.3 C3P0连接池
C3P0 第三方库,
内部实现了连接池技术.
package my; import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Date; import com.mchange.v2.c3p0.ComboPooledDataSource; public class SchoolDB
{
// 全局对象
static ComboPooledDataSource cpds = new ComboPooledDataSource(); public void testQuery() throws Exception
{
// 一个Connection代表一次访问
Connection conn = cpds.getConnection(); // 查询操作
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM student");
while(rs.next())
{
// 取出这一行记录
int id = rs.getInt("id");
String name = rs.getString("name");
String phone = rs.getString("phone"); // 可能为null
Date birthday = rs.getDate("birthday");
System.out.println(id + "\t" + name + "\t" + phone );
} conn.close();// 连接放回池子 } ///////////////////////////////
public static void main(String[] args)
{
try
{
SchoolDB db = new SchoolDB();
db.testQuery(); db.testQuery(); } catch (Exception e)
{
e.printStackTrace();
}
}
}
c3p0的实际使用. c3p0-config.xml的配置 //必须使用c3p0-config.xml这个名字. <?xml version="1.0" encoding="UTF-8"?>
<c3p0-config> <default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1/af_school</property>
<property name="user">root</property>
<property name="password">cqkill000</property> <property name="initialPoolSize">5</property>
<property name="minPoolSize">2</property>
<property name="maxPoolSize">10</property>
<property name="maxIdleTime">30</property>
</default-config> </c3p0-config> 第一次使用时:内部初始化连接池,需要一定实际.
-connection.close()没有关闭连接,只是返回连接池. 9.4 c3p0集成到afsql.
比如集成到afsql,mybatis,hibernate.
只需要将原来的DriverManager.getConnection(connectionUrl, username, password); 改为
static ComboPooledDataSource cpds = new ComboPooledDataSource();
Connection conn = cpds.getConnection(); 常用的连接池 Proxool c3p0 DBCP 10.1 字符串转义
问题:使用SQL插入一行,如果字符串含有单引号.
INSERT INTO `book` VALUES('小王','美丽'人'生'); //人字用单引号引上.
在SQL中加入\
INSERT INTO `book` VALUES('小王','美丽\'人\'生'); //在单引号前加入\
单引号需要转义
反斜杠需要转义 不同数据库对转义的规定定义可能不一样,但是原理是一样的 10.2 SQL注入的问题
一种利用程序漏洞恶意攻击.
系统登录的校验
例如:登录系统时.
-用户输入:用户名,密码
-后台从数据库校验,如果用户名密码匹配,则登录入系统,否则提示登录失败. SQL注入手段攻击系统
String username = "a' OR '1'='1";
String password = "b' OR '1'='1"; a' OR '1'='1 使用SQL语句判断后半部分 1=1,达成登录条件.
SQL注入预防.
可见,SQL语句拼写不规范时,可能受到攻击:
所以:
1.总是给值字段加上单引号
2.总是对值进行转义.
即使用规范的SQL语法,不会受到SQL注入攻击. 11.1 获取表的结构
information_schema.中描述了数据库,表,列的信息
数据库:schemate , 表:tables ,列:columns
例如:访问tables表
SELECT * FROM `tables` WHERE tbale_schemate='af_school'; 访问columns表
SELECT * FROM `tables` WHERE tbale_schemate='af_school' AND table_name='student'; 用代码获取.
public class Test
{
// schemaName : 数据库名
// 功能: 传入数据库名,自动查询下面有多个表
public static void showTables(String schemaName) throws Exception
{
// 连接到information_schema库
String username= "root";
String password = "a1b2c3";
String connectionUrl = "jdbc:mysql://127.0.0.1:3306/information_schema?useUnicode=true&characterEncoding=UTF-8"; Connection conn = DriverManager.getConnection(connectionUrl, username, password);
System.out.println("连接成功!"); ///////////////////////////////////////////////
// 拼凑SQL
AfSqlWhere where = new AfSqlWhere();
where.add2("TABLE_SCHEMA", schemaName);
String sql = "SELECT `TABLE_NAME` FROM `TABLES` " + where;
System.out.println("SQL: " + sql); // 执行SQL
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql) ; // 显示结果
while(rs.next())
{
String tableName = rs.getString("TABLE_NAME"); System.out.println("表: " + tableName );
} //////////////////////////////////////////////
conn.close();
System.out.println("关闭连接!");
} // schemaName : 数据库名
// 功能: 传入数据库名,自动查询下面有多个表
public static void showColumns(String schemaName, String tableName) throws Exception
{
// 连接到information_schema库
String username= "root";
String password = "a1b2c3";
String connectionUrl = "jdbc:mysql://127.0.0.1:3306/information_schema?useUnicode=true&characterEncoding=UTF-8"; Connection conn = DriverManager.getConnection(connectionUrl, username, password);
System.out.println("连接成功!"); ///////////////////////////////////////////////
// 拼凑SQL
AfSqlWhere where = new AfSqlWhere();
where.add2("TABLE_SCHEMA", schemaName);
where.add2("TABLE_NAME", tableName);
String sql = "SELECT `COLUMN_NAME`,`DATA_TYPE` FROM `COLUMNS` " + where;
System.out.println("SQL: " + sql); // 执行SQL
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql) ; // 显示结果
while(rs.next())
{
String columnName = rs.getString("COLUMN_NAME");
String dataType = rs.getString("DATA_TYPE");
System.out.println("列名: " + columnName + ", \t类型:" + dataType );
} //////////////////////////////////////////////
conn.close();
System.out.println("关闭连接!");
} public static void main(String[] args)
{
try
{
// showTables("af_school"); showColumns("af_school", "student"); } catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
} } 绝大多数系统中,表的结构都是事先设计好的,中间不会发生变化,也不会再程序里创建表.
所以本章不是很重要. 11.2 自动生成POJO类
在information_schema中描述了数据库,表,列的信息.从而可以自动生成POJO类
=>数据库名
=>自动获取所以table信息
=>自动获取每个table下的列名和列类型
=>有了表名,列名+列类型,自动创建一个POJO类. 13.1 SQLite
SQLite特点
1.所以表数据存在一个独立的文件里
2.本地访问,不需要安装服务器
3.数据量10万条以下
4.直接使用SQL语句 应用场景
1.嵌入式场景 例如:安卓app里可以使用
2.桌面单机程序.例如JavaFX可以用他存储一些本地数据. 和JSON的区别:SQLite时关系形数据库,支持SQL语句的增删改查.

MySQL基础和JDBC的更多相关文章

  1. 数据库及MYSQL基础(3)-JDBC

    教学视频链接:https://edu.aliyun.com/course/1694?spm=5176.11400004.0.0.29254768sg2H5P 程序文件链接:https://pan.ba ...

  2. java基础(11) -JDBC

    java基础(11) -JDBC jdbc 1.装载驱动 载入跟数据库建立连接的驱动 /* sql server: String className ="com.microsoft.sqls ...

  3. JavaSE基础之JDBC

    JavaSE基础之JDBC 1.JDBC 的步骤: ①加载数据库驱动: a.MySQL:com.mysql.jdbc.Driver: b.SQLServer:com.microsoft.jdbc.sq ...

  4. MySQL基础之事务编程学习笔记

    MySQL基础之事务编程学习笔记 在学习<MySQL技术内幕:SQL编程>一书,并做了笔记.本博客内容是自己学了<MySQL技术内幕:SQL编程>事务编程一章之后,根据自己的理 ...

  5. MySQL 基础知识梳理

    MySQL 的安装方式有多种,但是对于不同场景,会有最适合该场景的 MySQL 安装方式,下面就介绍一下 MySQL 常见的安装方法,包括 rpm 安装,yum 安装,通用二进制安装以及源码编译安装, ...

  6. Mysql基础代码(不断完善中)

    Mysql基础代码,不断完善中~ /* 启动MySQL */ net start mysql /* 连接与断开服务器 */ mysql -h 地址 -P 端口 -u 用户名 -p 密码 /* 跳过权限 ...

  7. MYSQL基础操作

    MYSQL基础操作 [TOC] 1.基本定义 1.1.关系型数据库系统 关系型数据库系统是建立在关系模型上的数据库系统 什么是关系模型呢? 1.数据结构可以规定,同类数据结构一致,就是一个二维的表格 ...

  8. 【夯实Mysql基础】记一次mysql语句的优化过程

    1. [事件起因] 今天在做项目的时候,发现提供给客户端的接口时间很慢,达到了2秒多,我第一时间,抓了接口,看了运行的sql,发现就是 2个sql慢,分别占了1秒多. 一个sql是 链接了5个表同时使 ...

  9. MySQL基础(非常全)

    MySQL基础 一.MySQL概述 1.什么是数据库 ? 答:数据的仓库,如:在ATM的示例中我们创建了一个 db 目录,称其为数据库 2.什么是 MySQL.Oracle.SQLite.Access ...

随机推荐

  1. Spring Security http标签的use-expressions="true"属性

    如果声明为true,那么在access属性要用hasRole()这样写: <intercept-url pattern="/secure/extreme/**" access ...

  2. 公司中springcloud项目遇到的问题

    1.更改maven的.m2下的settings.xml文件,程序就可以运行,是不是很神奇?

  3. HBASE的Java与Javaweb(采用MVC模式)实现增删改查附带源码

    项目文件截图 Java运行截图 package domain; import java.io.IOException; import java.util.ArrayList; import java. ...

  4. ClientImageViewController

    package com.vcredit.ddcash.server.web.controller.common; import com.vcredit.ddcash.server.commons.mo ...

  5. 数据库的相关语句(where,order by)

    select * from EMP t-- t列的别名--返回所有列 select ename || sal as HEHE from emp;--列的合并(使用连接) select concat(e ...

  6. 一招制敌 - 玩转 AngularJS 指令的 Scope (作用域),讲得特别好

    学习了AngularJS挺长时间,最近再次回首看看指令这部分的时候,觉得比自己刚开始学习的时候理解的更加深入了,尤其是指令的作用域这部分. 步入正题: 每当一个指令被创建的时候,都会有这样一个选择,是 ...

  7. odoo二次开发 tips

    1.model属性 每个对象(即class)一般由字段(变量)和函数组成,每个对象对应着数据库中的一张表,驼峰命名方式 models.Model 基础模块,会根据字段和模型名在后台数据库生成对应得表文 ...

  8. Spring Boot核心注解@SpringBootApplication

    一.作用   @SpringBootApplication是一个组合注解,用于快捷配置启动类. 二.用法   可配置多个启动类,但启动时需选择以哪个类作为启动类来启动项目. 三.拆解 1.拆解     ...

  9. TZOJ:区间问题

    描述 有n项工作,每项工作分别在 si时间开始,ti时间结束.对于每项工作你选择参与与否,如果选择 了参与,那么自始至终就必须全程参与.参与工作的时间段不可以重叠(即使是开始的瞬间和结束的瞬间重叠也是 ...

  10. iOS 如果页面 A 跳转到 页面 B,A 的 viewDidDisappear 方法和 B 的 viewDidAppear 方法哪个先调用?

    如果页面 A 跳转到 页面 B,A 的 viewDidDisappear 方法和 B 的 viewDidAppear 方法哪个先调用? 1. - (void)pushViewController:(U ...