目录
今日事:
1、前后端分离(常见的是前端写静态页面,后端套用模板)
2、前端开发中的MVC/MVP/MVVM模式
一、数据库(MySql,Oracle,SQL Server)(基本的数据库操作语句,sql语句,存储过程,触发器)(JDBC编程)
1、sql语句——(sql结构化查询语言:structural query language)
2、MySql
3、Oracle
4、JDBC编程(Java中唯二基1的,ResultSet,rs.get(1);,PreparedStatement,ps.setFloat(1,313.0f);)
一、数据库(MySql,Oracle,SQL Server)(基本的数据库操作语句,sql语句,存储过程,触发器)(JDBC编程)
二、Java基础知识
三、中间件(基础的中间件环境部署问题)(tomcat,weblogic)
四、Java web应用程序开发(jsp,servlet,filter),接口开发
五、Java,HTML,JavaScript,Ajax,xml,css,JSON,jQuery,webservice
六、SSH,SSM(spring应用和设计模式),springboot,springcloud,微服务,MVC
七、Java多线程,高并发,同步,网络通信, JPA
八、分布式计算,数据挖掘
九、计算机网络,TCP/IP,可复用开发理念
十、plsql,navicat,maven,git,svn,redis,负载均衡
十一、OOP面向对象编程,OOD,ERP(企业资源计划),CRM(客户关系管理系统),ORM(关系型数据库)
十二、C/S,B/S,新兴技术(云计算,SaaS,区块链,大数据,人工智能等)
十三、Linux常用命令,Hadoop,dockers,dubbo
十四、测试管理工具QC,loadrunner;EXT,python,JSTL(EL,OGNL)
十五、前端框架(bootstrap,vue,node.js,webpack,爬虫,网络算法(神经网络算法))
十六、优化
今日事:
1、前后端分离(常见的是前端写静态页面,后端套用模板)
- 程序的本质就是对数据的增删改查CRUD(create,retrieve,update,delete)
- 前后端分离就是把数据操作和显示分离出来。前端专注做数据显示,后端专注做数据的操作。前端发送数据,后端修改
- 后端本质是进行数据库的连接,对数据进行操作,业务分析与逻辑映射
- 后端提供接口给前端调用,来触发后端对数据的操作
2、前端开发中的MVC/MVP/MVVM模式
MVC/MVP/MVVM都是常见的软件架构设计模式(Architectural Pattern),通过分离关注点来改进代码的组织方式
不同于设计模式(Design Pattern):只为解决某类问题而总结出的抽象方法。 一种架构模式通常使用多种设计模式
MVC:允许在不改变视图的情况下改变视图对用户输入的相应方式,用户对view的操作交给controller处理,在controller中响应view的事件,调用model的接口对数据进行操作,一旦model发生变化便通知相关视图进行更新。
- model层:封装业务逻辑数据和对数据的处理方法(创建对象,封装数据,创建操作方法);一旦数据变化,model通知有关视图
model和view之间使用观察者模式,view事先在model上注册,进而观察model,以便更新在model上发生变化的数据
- view层:负责数据的显示(获取元素并渲染数据)
view和controller之间使用了策略模式,view引入controller的实例来实现特定的响应策略(如按钮的click事件)
- controller层:是模型视图之间的纽带,mvc将响应机制封装在controller对象中,当用户和应用产生交互,c层的事件触发器工作
缺点:业务逻辑集中在c层,使其臃肿,c与v连接紧密,复用性低,多view共用一个c困难
MVP(Model-View-Presenter):是mvc的改良,c/p业务逻辑控制,m管理数据与操作,v负责数据显示
- mvc中v可直接访问m,mvp中不可以,而是通过为presenter提供接口,让p去更新m,再通过观察者模式更新v
- mvp解耦v和m,完全分离视图和模型,可将v抽离做成组件,为上层操作提供一系列接口即可
- mvp定义p和v之间的接口,用户对v的操作都转移到了p,p通知m更新后,p调用v提供的接口依据m更新视图。
缺点:在p中除业务逻辑外,还有大量v与m之间的数据同步代码,且没有数据绑定,视图过多时,p繁重且须随之改动
mvvm(Model-View-ViewModel):ViewModel即model of view视图的模型。
mvvm把view和model的同步逻辑自动化了,交给框架所提供的数据绑定功能进行负责,view显示的数据对应的是model的哪部分
- model:数据层,类似于json数据对象,仅关注数据本身,不关心行为(格式化数据由view负责)
- view:通过使用模板语法来声明式的将数据渲染进DOM,当viewmodel对model进行更新时,会通过数据绑定更新到 view
- viewmodel:业务逻辑,数据绑定(双向数据绑定:类似于一个模板引擎,根据数据变更实时渲染)
数据劫持vue,发布-订阅模式knockout,backbone,脏值检查angular
简化业务与界面的依赖,解决数据频繁更新,低耦合,可重用性高
一、数据库(MySql,Oracle,SQL Server)(基本的数据库操作语句,sql语句,存储过程,触发器)(JDBC编程)
建表:先创建没有外键关联的表
1、sql语句——(sql结构化查询语言:structural query language)
sql对大小写不敏感,
句末;分号可不使用,分号是分割每条sql的标准方法,可在对服务器的相同请求中执行一条以上的语句。
sql使用单引号来环绕文本值,数值不需要
- DML:数据操作语言(insert into,delete,update,select)
- DDL:数据定义语言(create database/table/index,alter database/table,drop database/table/index
- 去除列中的重复值:select distinct name from student;
- <>不等于!= between and/or(可通过括号组合使用) like
- order by子句:用于根据指定的列对结果集进行排序,默认为asc升序,降序为desc
- insert into 表(列1,列2...) values(值1,值2...);(插入数据)
- update 表 set 列1=值1,列2=值2 where id=1;(修改数据)
- delete from 表 where id=1; delete from 表; delete * from 表;
- SQL top:规定要返回的记录的数目。
MySQL——select * from tableName limit number(数量); Oracle——select * from tableName where rownum <= number;
- select top 2 * from tableName;(选取头两条) select top 50 percent * from tableName;(选取50%的记录)
- select * from student where name (not) like 'wl%' / '%wl' / '%wl%';(like操作符用于where子句中搜索列中的指定模式)
- (通配符):%替代一个或多个字符, _仅替代一个字符, [charlist]字符列中的任一字符, ><[^charlist] / [!charlist](不)
'[ALN]%' 以A,L,N开头, '[!ALN]' 不以其开头
in操作符允许在where子句中规定多个值 select * from student where name in ('a','b')
between ... and选取介于两个值之间的数据范围。(可以是数值,文本,日期等) 范围之外not between ... and
列/表别名: (as) alias
SQL join :(用于根据两个或多个表中的列之间的关系,从这些表中查询数据。
- select * from a inner join b on a.id = b.id order by a.id;(inner join内连接,表中至少一个匹配返回行)
- select * from a left outer join b on a.id = b.id order by a.id;(left join左外连接,从左表返回所有行,即使右表中无匹 配行)
- (right outer join右外连接,从右表返回所有行)
- (full outer join全外连接,从左右表返回所有行)
union:合并两个或多个select语句的结果集,(union内部的select语句须有相同数量的列,列数据类型相似,列顺序相同)
默认union选取不同的值(去重复),允许重复请用union all
select into从一个表中选取数据,插入到另一个表中,常用于创建表的备份文件或用于对记录进行存档
select * into s3 in 'backup.mdb' from s1 inner join s2 on s1.id = s2.id;(从一个以上的表中选取数据插入到另一个库的表中)
SQL Constraints(约束)可在创建表时规定约束(create table),或在表创建之后(alter table)
- not null非空,
- unique约束唯一标识数据库表中的每条记录 unique(id)——MySQL unique——Oracle/SQL server/MS Access
多个列定义:constraint a unique(id,name)
表定义后创建unique约束:alter table student add unique(id); alter table student add constraint a unique(id,name);
撤销unique约束:alter table student drop index a;——MySQL , alter table student drop constraint a;——SQL server/Oracle/
- primary key:约束唯一标识数据库表中的每条记录,必须包含唯一值,主键列不能包含null值,每个表有且仅有一个主键。
primary key(id)——MySQL, primary key——Oracle/SQL server/MS Access
为多个列定义:constraint pk_pid primary key (id,name);
表已存在后创建:alter table student add primary key(id);
重命名且为多个列定义:alter table student add constraint pk_pid primary key(id,name);(须把主键声明为not null)
撤销:alter table student drop primary key;——MySQL, alter table student drop constraint pk_pid;——SQL server/Oracle
- foreign key:(一个表中的外键指向另一个表中的主键),用于预防破坏表之间连接的动作,防止非法数据插入外键列。
foreign key(id_p) references person(id_p)——MySQL, id_p int foreign key references person(id_p)——Oracle/SQL server
命名外键约束:contraint fk_p_s foreign key(id_p) references person(id_p),
表已存在创建:alter table student add foreign key(id_p) references person(id_p)
重命名:alter table student add constraint fk_p_s foreign key(id_p) references person(id_p)
撤销:alter table student drop foreign key fk_p_s——MySQL, alter table student drop constraint fk_p_s——Oracle/SQL se
- check检查约束:用于限制列中值的范围。(列只允许特定的值,表中会在特定的列中对值进行限制)
check (id_p>0)——MySQL, id_p int not null check(id_p>0)——SQL server/Oracle/MS Access
命名check约束及为多个列定义约束:constraint chk_p check(id_p>0 and city='zz')
表已存在创建:alter table person add check(id_p>0);
命名check约束,多个列:alter table person add contraint chk_p check(id_p>0 and city='zz');
撤销:alter table person drop check chk_p;——MySQL, alter table person drop constraint chk_p;——Oracle/SQL server
- default:向列中插入默认值。(可使用类似getdate()这样的函数,default插入系统值) orderDate date default getdate(),
表已存在创建:alter table person alter city set default 'sh';——MySQL, alter table person alter column city set default 'sh';
撤销:alter table person alter city drop default;——MySQL, alter table person alter column city drop default;——Oracle/
create index:在表中创建索引。(在不读取整个表时,索引使数据库应用程序更快地查找数据)(看不到,能加速搜索/查询)
注释:更新一个包含索引的表需要比更新一个没有索引的表更多的时间,这是由于索引本身也需要更新。因此,理想的做法是仅仅在常常被搜索的列(以及表)上面创建索引。
create (unique) index 索引名 on person (需要索引的列1,列2 [desc]);
unique唯一的索引意味着两个行不能拥有相同的索引值。 desc降序索引某个列的值, 可以有多个列
drop:删除索引,表,数据库
drop database 数据库名; drop table 表名; truncate table 表名;(仅删除数据,结构不变)
drop index 索引名;——Oracle。 alter table person drop index 索引名;——MySQL。
alter:用于在已有的表中添加,修改或删除列。
alter table person add 列名 列类型; alter table person drop column 列名; alter table person alter column 列名 列类型;
auto_increment:自动增长(在新纪录插入表时生成一个唯一的数字)(默认值为1)——MySQL
让auto_increment 序列以其他值起始:alter table person auto_increment = 100;——MySQL
在Oracle中需先创建序列sequence: create sequence 名 minvalue 1 start with 1 increment by 1 cache 10
insert into person (id_p,name,city) values(名.nextval,'hjj','zz');
view:视图,可视化的表。(是基于sql语句结果集的可视化的表),(向用户精确的提交我们希望提交的数据)
创建视图:选取表中所有单位价格高于平均单位价格的数据
create view [products above average price] as select * from product where price>(select avg(price) from product);
select * from [projects above average price] where name='wl';
视图来自于另一个视图中选取的数据:
create view [a from b] as select distinct name,sum(price) as aprice from [b from c] group by name;
更新视图:
create/replace view [products above average price] as select * from products where price>(select avg(price) from product);
撤销视图:
drop view [products above average price]
SQL Date:(若希望使查询简单且易维护,请不要在日期中使用时间部分)
MySQL——date:yyyy-mm-dd, datetime:yyyy-mm-dd hh:mm:ss, timestamp yyyy-mm-dd hh:mm:ss year:yyyy或yy
SQL null:null值是遗漏的未知数据。默认表列可以存放null值。(null与0是不等价的),(用作未知的或不适用的值的占位符)
测试null值,使用is null 或is not null select * from student name is (not) null
null数据运算处理:select name ,price1*(p1+ifnull(p2,0)) from student;——MySQL(或是使用coalesce(p2,0)处理)
nvl(p2,0)——Oracle, isnull(p2,0)——SQL server/MS Access
MySQL数据类型:三种主要的是文本,数字和日期/时间类型。
SQL函数function:(sql拥有很多可用于计数和计算的内建函数),(函数类型:aggregate function,scalar function)
在分组聚合操作中,在查询列时,除了聚合函数运算外,其他表达式必须包含在group by子句中
使用GROUP BY进行分组查询时应注意如下问题: (1)GROUP BY子句中的列名只能是FROM子句所列表的列名,不能是列的别名。 (2)使用GROUP BY子句后,SELECT子句的目标列表达式所涉及的列必须满足:要么在GROUP BY子句中,要么在在某个统计函数中。 (3)如果分组后还要求按一定的条件对这些组进行筛选,最终只输出满足指定条件的组,则可以使用HAVING短语指定筛选条件。
(按姓名分组)查询同名的人有多少个:select name count(*) from student order by name; 张三,2 李四,1
列分组:select 列1,列2 from student order by 列1,列2
分组聚合:(男女生平均年龄)select sex,avg(age) as avgAge from student group by sex;
(男女生人数)select sex,count(sex) as 人数 from student group by sex;
SELECT Customer,OrderDate,SUM(OrderPrice) FROM Orders GROUP BY Customer,OrderDate
与having子句:对分组筛选后的结果再次筛选(having子句中可包含聚合函数)
(按性别分组,求平均年龄,并查平均年龄大于21的数据)select avg(age),sex from student group by sex having avg(age)>21
与order by:select 学号,avg(成绩) as 平均成绩 from grade group by 学号 order by 平均成绩;
aggregate合计函数:操作面向一系列的值,返回一个单一的值。
avg(column),count(column),count(*),first(column),last(column),max(column),min(column),sum(column)
count(distinct column)
scalar标量函数:操作面向单一值,并返回一个基于输入值的单一值。
SELECT Customer,SUM(OrderPrice) FROM Orders
WHERE Customer='Bush' OR Customer='Adams'
GROUP BY Customer
HAVING SUM(OrderPrice)>1500
mid():从文本字段中提取字符。 mid(name,1,[length]) ucase(), lcase(), len(),
round():把数值字段舍入为指定的小数位数。 round(price,2)
now(): select * now() as selTime from student;
format():对字段的显示进行格式化 select * format(now(),'yyyy-mm-dd') as selTime from student;
2、MySql
create database databaseName;(创建数据库)
use databaseName;(使用数据库)
drop table if exists tableName;(删除表)
create table tableName(id int(11) not null auto_increment comment 'id',...)engine=innodb comment 'table' default=utf8;(建表)
constraint fk_关联表名_本表名 foreign key(外键字段) references 关联表(id); //外键关联
insert into tableName values(1,'qq',2);(插入数据)
select count(*),* from tableName limit start,count;(分页查询)
update tableName set password=121 where id=1;(修改数据)
delete from tableName where id=1;(删除数据)
"ser/bin/mysqldump.exe" -uroot -padmin -hlocalhost -p3306 test(备份的数据库名) -r d:\test.sql(备份后的文件);(mysql备份)
"ser/bin/mysql.ext" -uroot -padmin test < d:\test.sql;(MySQL还原)
MySql——innodb MySQL5.7默认innodb;(有简单的方式)
(某个表:show table status from 数据库名;(查看表类型),alter table hero engine = innodb;(修改表类型)
检查是否开启innodb: show variables like 'have_%'; 在结果中的have_innodb,如果显示为YES,即表示启动了。 如果是NO或者DISABLED表示未启动。如果不存在也表示未启动。
首先执行命令停止MySQL net stop mysql;
定位到D:\tools\MYSQL\mysql-5.1.57-win32\data 目录下,找到这3个文件 ib_logfile0 ib_logfile1 ibdata1备份后删除
在配置文件中添加 打开文件:D:\tools\MYSQL\mysql-5.1.57-win32\my.ini 添加一行 default-storage-engine=InnoDB
启动MySQL net start; 再检测: show variables like 'have_%';
MySQL修改密码:
使用当前密码进入MySQL "...\mysql.exe" -uroot -padmin; mysql -hlocalhost -uroot -padmin;
修改: set password for root@localhost = password('121');
装卸:
控制面板--装卸,删除C盘MySQL目录(C:\Program Files\MySQL),删除my.ini在C:\WINDOWS目录下,
运行注册表:win+r regedit
删除key1:HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Eventlog\Application\MySQL
删除key2:HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Services\Eventlog\Application \MySQL
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\MySQL
删除ProgramData下的文件:C:\ProgramData\MySQL Server 5.5(默认隐藏)
C:\Documents and Settings\All Users\Application Data\MySQL(XP和win7对应的文件)
3、Oracle
服务器安装:默认安装(非中文,非空格) 管理员密码一般输入sys CTRL+F8执行sql语句
客户端安装:pl-sql developer。 登录:sys/sys orcl connect as sysdba(navicat连接时,注意将角色改为sysdba)
序列号: KF46-6HV4-2UAC-YYEB-R82Y-6JB4-JVNH-WH QWLJ-S6UT-WC93-5XW7-WK3Q-F7KA-SBEU-XL
字符串连接符: select last_name || ' ' || first_name '姓名' from student;(别名as可选,单引多引可选)
条件限定:distinct,<>不等于,between ... and,IN(值1,值2),like(%,_) 逻辑条件:and,or,not
查询所在部门为null的员工,即该员工暂时还未分配工作部门:select * from hr.employees where department_id is null
排序查询:order by 关联查询:left join 表关联,on指定关联字段。
统计函数:count,max,min,avg 分组查询:group by。 having对分组函数进行条件判断。
select avg(salary),e.department_id,e.first_name from hr.employees e group by e.department_id,e.first_name
having avg(salary)>4200
子查询:同时执行多条sql语句(将一条sql语句的查询结果作为条件来执行另一条sql语句)
Oracle使用rownum进行分页查询:
查出薪水最高的5-10条数据:
select e2.* from (select rownum r , e1.* from (select e.* from hr e order by e.salary) e1)e2 where e2.r>=5 and e2.r<=10;
Oracle表字段类型:varchar和varchar2的区别,两种都是变长的,对于汉字(unicode)的处理有区别:
varchar如果放的是英文和数字,就用一个字节存放,如果是汉字(unicode),就用两个字节
varchar2 统一使用两个字节, 一般都直接使用varchar2,使用varchar很少了
插入数据:insert into table() values(); commit;(提交这一次插入行为,否则数据库不生效)
Oracle序列:sequence,通常被用来作为id插入到表中。
创建: create sequence hero_seq increment by 1 start with 1 maxvalue 999999 cache 10
使用: select hero_seq.nextval from dual(获取hero_seq下个值) select hero_seq.currval from dual(获取hero_seq当前值)
插入:insert into hero (id,name,hp,mp,damage,armor) values(hero_seq.nextval,'炸弹人',450,200,45,3);(作为id插入表中)
修改字段:update hero set damage =46,armor = 5 where id=3;
删除数据:delete from hero where id=1;(删除操作是可以回滚的,只要在提交之前,进行回滚就可把删除的数据还原)
truncate table hero;(truncate比delete更快,更彻底,不能回复,不能回滚:删除表里所有记录)
alter修改表结构: alter table hero add (kills number);(增加新列) alter table hero modify(name varchar2(300));(修改列)
alter table hero drop column kills;(删除列:执行删除需要权限)
删除表:drop table hero;(不能回滚)
约束:unique,not null,primary key,foreign key
给约束命名:constraint uk_hero(表名)_name(字段名) unique (name);
给已存在的表增加约束:alter table hero add constraint pk_hero_id primary key (id)
删除约束:alter table hero drop constraint uk_hero_name
外键约束:constraint fk_killer_hero foreign key (killerid) references hero(id), (击杀次数)
constraint fk_killed_hero foreign key (killedid) references hero(id) (被击杀次数)
Oracle视图: create view herosimple as ( select id, name from hero ) select * from herosimple;
创建用户:登录plsql——左边菜单,选择users右键new——用户信息,对象权限,角色权限,系统权限——apply应用
登录验证是否创建成功:身份改为normal即可(这样使用fzy身份创建的表,才可以通过jdbc访问)
若遇到超出表空间限额,则执行sql:alter user bigsword quota unlimited on users;
plsql远程连接:E:\oracle11g\product\11.2.0\dbhome_1\NETWORK\ADMIN下的tnsnames.ora配置文件修改
参考 https://jingyan.baidu.com/article/b0b63dbfcd34834a4930704a.html
4、JDBC编程(Java中唯二基1的,ResultSet,rs.get(1);,PreparedStatement,ps.setFloat(1,313.0f);)
JDBC:(Java DataBase Connection) 是通过JAVA访问数据库
导入驱动连接jar包(右键project->property->java build path->libaries->add external jars)
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBC {
//导包步骤:右键project->property->java build path->libaries->add external jars
//import的都是java.sql.*;
public static void main(String[] args) {
Connection c = null;
Statement st = null;
try {
/*
* 1、初始化驱动:若忘记则会抛出ClassNotFoundException
* Class.forName是把这个类加载到JVM中,加载的时候,就会执行其中的静态初始化块,完成驱动的初始化的相关工作
*/
Class.forName("com.mysql.jdbc.Driver");
/*
* 2.建立与数据库的连接
* 需要ip,端口号,数据库名,编码方式,账号,密码
* 若有误会抛出SQLException
*/
c =DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8","root","123456"
);
/*
* 3、创建执行SQL语句的Statement对象
* 根据连接创建sql执行对象
*/
st = c.createStatement();
/*
* 4、准备sql语句(字符串要用单引号)
*/
String sql =
"insert into user1 values"
+ "(null,"+"'fzy'"+","+"'fzy111'"+","+"'22'"+")";
/*
* 5、s.execute()执行sql语句。
*/
st.execute(sql);
} catch (ClassNotFoundException e) {
// TODO: handle exception
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
/*
* 6、数据库的连接是有限资源,操作结束后,关闭。(采用就近原则)
*/
if(st != null)
try {
st.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(c != null)
try {
c.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
使用try-with-resource的方式自动关闭连接(jdk7特性) (关闭流方式) Connection和Statement都实现了AutoCloseable接口
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* try-with-resource关闭流方式
* @author fzywhy
*
*/
public class JDBCtry {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try (
Connection c =
DriverManager.getConnection("jdbc:mysql://172.0.0.1:3306/test?characterEncoding=UTF-8","root","123456");
Statement st = c.createStatement();
)
{
String sql = "insert into user1 values(null,"+"'fzy'"+","+"'fzy111'"+","+"'22'"+")";
st.execute(sql);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
查询st.executeQuery(sql);
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCselect {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try (
Connection c =
DriverManager.getConnection("jdbc:mysql://172.0.0.1:3306/test?characterEncoding=UTF-8","root","123456");
Statement st = c.createStatement();
)
{
// String sql = "insert into user1 values(null,"+"'fzy'"+","+"'fzy111'"+","+"'22'"+")";
// st.execute(sql);
/*
* st.executeQuery(sql)执行sql查询语句
*/
String sql = "select * from user1";
//执行查询语句,并把结果集合返回给ResultSet
ResultSet rs = st.executeQuery(sql);
while(rs.next()) {
int id = rs.getInt("id");//可使用字段名
String username = rs.getString(2);//也可使用字段的顺序下标
String password = rs.getString(3);
String perms = rs.getString("perms");
System.out.printf("%d\t%s\t%s\t%s\n", id,username,password,perms);
}
//statement关闭的时候,自动关闭ResultSet
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
判断账号密码是否正确:
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJDBC {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
"root", "admin");
Statement s = c.createStatement();
) {
String name = "dashen";
//正确的密码是:thisispassword
String password = "thisispassword1";
String sql = "select * from user where name = '" + name +"' and password = '" + password+"'";
// 执行查询语句,并把结果集返回给ResultSet
ResultSet rs = s.executeQuery(sql);
if(rs.next())
System.out.println("账号密码正确");
else
System.out.println("账号密码错误");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
获取总数:
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJDBC {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
"root", "admin"); Statement s = c.createStatement();) {
String sql = "select count(*) from hero";
ResultSet rs = s.executeQuery(sql);
int total = 0;
while (rs.next()) {
total = rs.getInt(1);
}
System.out.println("表Hero中总共有:" + total+" 条数据");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
分页查询:
package how;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJDBC {
public static void main(String[] args) {
list(0,6);
}
public static void list(int start, int count){
//进制转化
int cf=0;
int index=0;
int w=start;
while(w!=0){
w/=10;
int wei=start%10;
index+=(Math.pow(2, cf)*wei);
cf++;
}
index+=1;
//执行sql语句
String sql="select * from hero limit "+index+","+count;
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try(Connection c = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
Statement s = c.createStatement();){
ResultSet rs = s.executeQuery(sql);
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString(2);
float hp = rs.getFloat("hp");
int damage = rs.getInt(4);
System.out.printf("%d\t%s\t%f\t%d%n", id, name, hp, damage);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
预编译PreparedStatement:(优点:1、使用参数设置,不需字符串拼接,可读性和维护性好,不易犯错。
2、性能更优:有预编译机制,性能更快。数据库对带?的sql进行预编译,每次执行,只需要传输参数到数据库端即可。 比较:网络传输量比statement小;数据库不需要再进行编译,响应更快。
3、防止SQL注入式攻击(字符串拼接where条件恒成立),PreparedStatement使用参数设置)
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestJDBC {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
String sql = "insert into hero values(null,?,?,?)";
try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
// 根据sql语句创建PreparedStatement
PreparedStatement ps = c.prepareStatement(sql);
) {
// 设置参数
ps.setString(1, "提莫");
ps.setFloat(2, 313.0f);
ps.setInt(3, 50);
// 执行
ps.execute();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
execute与executeUpdate都可以执行增删改
不同点:execute可执行查询语句,通过getResultSet取出结果集;executeUpdate不能执行查询语句
execute返回Boolean类型,true表示执行的是select,false表示执行的是增删改
executeUpdate返回的是int,表示有多少条数据受到了影响。
获取自增长id:
PreparedStatement ps = c.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);//确保会返回自增长id
ResultSet rs = ps.getGeneratedKeys(); if(rs.next){int id = rs.getInt(1);}
获取表的元数据:
元数据:和数据库服务器相关的数据(egg:数据库版本,哪些表,哪些字段,字段类型)
package jdbc;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJDBC {
public static void main(String[] args) throws Exception {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");) {
// 查看数据库层面的元数据
// 即数据库服务器版本,驱动版本,都有哪些数据库等等
DatabaseMetaData dbmd = c.getMetaData();
// 获取数据库服务器产品名称
System.out.println("数据库产品名称:\t"+dbmd.getDatabaseProductName());
// 获取数据库服务器产品版本号
System.out.println("数据库产品版本:\t"+dbmd.getDatabaseProductVersion());
// 获取数据库服务器用作类别和表名之间的分隔符 如test.user
System.out.println("数据库和表分隔符:\t"+dbmd.getCatalogSeparator());
// 获取驱动版本
System.out.println("驱动版本:\t"+dbmd.getDriverVersion());
System.out.println("可用的数据库列表:");
// 获取数据库名称
ResultSet rs = dbmd.getCatalogs();
while (rs.next()) {
System.out.println("数据库名称:\t"+rs.getString(1));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
JDBC事务提交:保护数据的完整性,安全性和正确性。
表类型必须是innodb:show table status from 数据库名; alter table hero engine = innodb;
在事务中的多个操作,要么都成功,要么都失败。
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJDBC {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
Statement s = c.createStatement();) {
// 有事务的前提下
// 在事务中的多个操作,要么都成功,要么都失败
c.setAutoCommit(false);
// 加血的SQL
String sql1 = "update hero set hp = hp +1 where id = 22";
s.execute(sql1);
// 减血的SQL
// 不小心写错写成了 updata(而非update)
String sql2 = "updata hero set hp = hp -1 where id = 22";
s.execute(sql2);
// 手动提交
c.commit();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
JDBC:ORM=Object Relationship Database Mapping 对象和关系数据库的映射(一个对象,对应数据库里的一条记录)
package how;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class TestJDBC {
public static Hero get(int id) {
Hero hero = null;
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
Statement s = c.createStatement();) {
String sql = "select * from hero where id = " + id;
ResultSet rs = s.executeQuery(sql);
// 因为id是唯一的,ResultSet最多只能有一条记录
// 所以使用if代替while
if (rs.next()) {
hero = new Hero();
String name = rs.getString(2);
float hp = rs.getFloat("hp");
int damage = rs.getInt(4);
hero.name = name;
hero.hp = hp;
hero.damage = damage;
hero.id = id;
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return hero;
}
//把一个Hero对象插入到数据库中
public static void add(Hero h){
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
Statement s = c.createStatement();){
String name=h.name;
float hp=h.hp;
int damage=h.damage;
//int id=h.id;
//这里id可以让它自动生成,如果自己定义的话,要判断该id是否被占用
String sql="insert into hero values(null,"+"'"+name+"',"+hp+","+damage+")";
s.execute(sql);
}catch(SQLException e){
e.printStackTrace();
}
}
//把这个Hero对象对应的数据删除掉
public static void delete(Hero h){
try{
Class.forName("com.mysql.jdbc.Driver");
}catch(ClassNotFoundException e){
e.printStackTrace();
}
try(Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
Statement s = c.createStatement();){
int id=h.id;
String sql = "delete from hero where id ="+id;
s.execute(sql);
}catch(SQLException e){
e.printStackTrace();
}
}
//更新这条Hero对象
public static void update(Hero h){
try{
Class.forName("com.mysql.jdbc.Driver");
}catch(ClassNotFoundException e){
e.printStackTrace();
}
try(Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
Statement s = c.createStatement();){
String name=h.name;
float hp=h.hp;
int damage=h.damage;
int id=h.id;
String sql = "update hero set name = '"+name+"',hp="+hp+",damage="+damage+" where id = "+id;
s.execute(sql);
}catch(SQLException e){
e.printStackTrace();
}
}
//把所有的Hero数据查询出来,转换为Hero对象后,放在一个集合中返回
public static List<Hero> list(){
try{
Class.forName("com.mysql.jdbc.Driver");
}catch(ClassNotFoundException e){
e.printStackTrace();
}
try(Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
Statement s = c.createStatement();){
String sql = "select * from hero";
ResultSet rs = s.executeQuery(sql);
List<Hero> l=new ArrayList<>();
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString(2);
float hp = rs.getFloat("hp");
int damage = rs.getInt(4);
Hero h= new Hero();
h.id=id;
h.name=name;
h.hp=hp;
h.damage=damage;
l.add(h);
}
return l;
}catch(SQLException e){
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
Hero h = get(107);
System.out.println(h.name);
Hero h1=new Hero();
h1.damage=55;
h1.hp=305;
h1.id=3;
h1.name="守望者";
add(h1);
delete(h);
Hero h2=new Hero();
h2.damage=55;
h2.hp=305;
h2.id=3;
h2.name="逝去者";
update(h2);
List<Hero> l=list();
System.out.println(l.size());
}
}
JDBC:DAO=Data Access Object数据访问对象
DAO接口:
package jdbc;
import java.util.List;
import charactor.Hero;
public interface DAO{
//增加
public void add(Hero hero);
//修改
public void update(Hero hero);
//删除
public void delete(int id);
//获取
public Hero get(int id);
//查询
public List<Hero> list();
//分页查询
public List<Hero> list(int start, int count);
}
HeroDao类实现dao接口并实现接口方法:(把数据库相关的操作都封装在这个类里面,其他地方看不到JDBC的代码)
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import charactor.Hero;
public class HeroDAO implements DAO{
//把驱动的初始化放在了此类的构造方法中(初始化驱动只需要执行一次)
public HeroDAO() {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//所有的数据库操作都需要先拿到一个数据库连接,有变化可只在此处更改(易维护,更简洁)
public Connection getConnection() throws SQLException {
return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8", "root",
"admin");
}
public int getTotal() {
int total = 0;
try (Connection c = getConnection(); Statement s = c.createStatement();) {
String sql = "select count(*) from hero";
ResultSet rs = s.executeQuery(sql);
while (rs.next()) {
total = rs.getInt(1);
}
System.out.println("total:" + total);
} catch (SQLException e) {
e.printStackTrace();
}
return total;
}
public void add(Hero hero) {
String sql = "insert into hero values(null,?,?,?)";
try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
ps.setString(1, hero.name);
ps.setFloat(2, hero.hp);
ps.setInt(3, hero.damage);
ps.execute();
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) {
int id = rs.getInt(1);
hero.id = id;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public void update(Hero hero) {
String sql = "update hero set name= ?, hp = ? , damage = ? where id = ?";
try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
ps.setString(1, hero.name);
ps.setFloat(2, hero.hp);
ps.setInt(3, hero.damage);
ps.setInt(4, hero.id);
ps.execute();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void delete(int id) {
try (Connection c = getConnection(); Statement s = c.createStatement();) {
String sql = "delete from hero where id = " + id;
s.execute(sql);
} catch (SQLException e) {
e.printStackTrace();
}
}
public Hero get(int id) {
Hero hero = null;
try (Connection c = getConnection(); Statement s = c.createStatement();) {
String sql = "select * from hero where id = " + id;
ResultSet rs = s.executeQuery(sql);
if (rs.next()) {
hero = new Hero();
String name = rs.getString(2);
float hp = rs.getFloat("hp");
int damage = rs.getInt(4);
hero.name = name;
hero.hp = hp;
hero.damage = damage;
hero.id = id;
}
} catch (SQLException e) {
e.printStackTrace();
}
return hero;
}
public List<Hero> list() {
return list(0, Short.MAX_VALUE);
}
public List<Hero> list(int start, int count) {
List<Hero> heros = new ArrayList<Hero>();
String sql = "select * from hero order by id desc limit ?,? ";
try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
ps.setInt(1, start);
ps.setInt(2, count);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Hero hero = new Hero();
int id = rs.getInt(1);
String name = rs.getString(2);
float hp = rs.getFloat("hp");
int damage = rs.getInt(4);
hero.id = id;
hero.name = name;
hero.hp = hp;
hero.damage = damage;
heros.add(hero);
}
} catch (SQLException e) {
e.printStackTrace();
}
return heros;
}
}
JDBC数据库连接池:(与线程池类似,但实现思路不一样)
每个数据库操作都需要创建一个连接,创建连接和关闭连接都比较消耗时间,多线程并发时会比较卡顿。
且一个数据库同时支持的连接总数是有限的,多线程并发量很大时,数据库连接总数就会消耗光,后续线程发起的DB连接失败。
连接池原理:在使用之前,创建好一定数量的连接,线程需要时向连接池借用连接,使用完毕后归还,供下一个或其他线程使用,多线程并发,连接池中的连接被借用完毕,其他线程会临时等待,直到有连接被归还,再继续使用,整个过程,连接不会被关闭,不断的被循环使用。
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class ConnectionPool {
List<Connection> cs = new ArrayList<Connection>();
int size;
//ConnectionPool() 构造方法约定了这个连接池一共有多少连接
public ConnectionPool(int size) {
this.size = size;
init();
}
/*
* 在init() 初始化方法中,创建了size条连接。 注意,这里不能使用try-with-resource这种自动关
* 闭连接的方式,因为连接恰恰需要保持不关闭状态,供后续循环使用
*/
public void init() {
//这里恰恰不能使用try-with-resource的方式,因为这些连接都需要是"活"的,不要被自动关闭了
try {
Class.forName("com.mysql.jdbc.Driver");
for (int i = 0; i < size; i++) {
Connection c = DriverManager
.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8", "root", "admin");
cs.add(c);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//getConnection, 判断是否为空,如果是空的就wait等待,否则就借用一条连接出去
public synchronized Connection getConnection() {
while (cs.isEmpty()) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Connection c = cs.remove(0);
return c;
}
/*
* returnConnection, 在使用完毕后,归还这个连接到连接池,并且在归还完毕后,调用
* notifyAll,通知那些等待的线程,有新的连接可以借用了。
*/
public synchronized void returnConnection(Connection c) {
cs.add(c);
this.notifyAll();
}
}
测试数据库连接池:
package jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import jdbc.ConnectionPool;
public class TestConnectionPool {
public static void main(String[] args) {
ConnectionPool cp = new ConnectionPool(3);
for (int i = 0; i < 100; i++) {
new WorkingThread("working thread" + i, cp).start();
}
}
}
class WorkingThread extends Thread {
private ConnectionPool cp;
public WorkingThread(String name, ConnectionPool cp) {
super(name);
this.cp = cp;
}
public void run() {
Connection c = cp.getConnection();
System.out.println(this.getName()+ ":\t 获取了一根连接,并开始工作" );
try (Statement st = c.createStatement()){
//模拟时耗1秒的数据库SQL语句
Thread.sleep(1000);
st.execute("select * from hero");
} catch (SQLException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
cp.returnConnection(c);
}
}