因为程序要连接数据库所以要先在自己电脑上装好Mysql数据库,操作数据库可以用Idea中内置的,也可以下Navicat来操作。我们现在默认是已经安装好数据库,并且注册好了,知道自己电脑数据库的root和密码。
第一部分 什么是JDBC
• JDBC: (Java DataBase Connectivity), 就是使用Java语言操作关系型数据库的一套API 即接口。
是各个数据库厂商去实现这套接口,提供数据库驱动jar包。
因为我们没有用maven或者springboot工程所以没有xml文件 不能直接引入依赖,所以我们要自己在项目中去导入Mysql的jar包,在mysql官网中下载MySQL :: Download Connector/J
当下载好了jar包,在项目结构中按照下面步骤导入jar包:
记得一定要勾选!
当外部库中有了,这步就成功了~
第二部分 在该项目中使用JDBC
我们先在mysql创建一个关于该项目的数据库 我这里用的命令行:
创建了一个名为test1的数据库;
在程序开始前:我们就需要先在Idea右侧面板中把数据库点开,选择Mysql
在这里输入账号密码和数据库的名称、测试、应用、确定。
数据库控制台就出来了,可以在里面输入SQL语句,当然在Idea中很方便,可以用图形化操作~
然后就可以创建项目中各种会用到的表,添加一些字段内容,以上就是在Idea中打开数据库的方法。如:
我们虽然打开了数据库但是程序还未连接上数据库,我们还需要在代码中配置一些数据库的信息。(关键点)
这段放在主函数上方,可以看到都是一些静态的变量 说明在程序中数据库信息是不变的。
并且这一段几乎都是在程序中写死的也叫硬代码(所以这也存在一些问题 后面会跟mybatis进行对比JDBC的缺点,就会发现为什么一般项目中不怎么用原始JDBC的原因)
//本地电脑数据库信息
static String driver = "com.mysql.cj.jdbc.Driver"; //配置mysql驱动
static String url = "jdbc:mysql://localhost:3306/market?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC";
static String username = "root";
static String password = "2004ywj0619";
static{
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
注意第二句的market是我电脑上的数据库名,你们要改成自己的数据库名;并且username和password也要改成自己的~
到这步已经配置好了数据库信息,但是还没有进行连接,我们在每次要使用数据库的时候才去进行连接,用完了要在结尾进行close(断开连接)比如我们来看一个登录login模块:
前面都是一些读入用户输入的代码,主要是从21行开始;
22行: 是用Connection的这个对象,通过传输我们之前定义好的url、username、password 进行对数据库的连接;
23行:获取操作数据库的对象 这里有个新来的Statement类和它相似的还有一个叫PrepareStatement,都可以用于执行修改和查询并获取结果集,他们之间有什么区别呢?简单来说①PrepareStatement比Statement更加安全,可以防止SQL注入攻击,因为数据库是允许用户输入操作的,那用户可能会试图去攻击、修改数据库,去公司删库跑路?这里的PreparedStatement
中它是用getset方法对属性进行了封装,只能通过getset方法去修改(就是我们课上在javabean中对每个属性进行getset方法一样)②PreparedStatement
可以预编译语句,处理性能更优!③Statement
的代码可读性较差
他们两个对象的返回值是一个结果集(ResultSet在26行),相当于把操作过后的数据放到一个集合中返回给数据库。
25行: 是编写该功能模块下会用到的SQL操作语句,比如在这个登录模块中 用户输入了用户名,我们就要把输入的用户名 拿去 和我们数据库中的用户名进行比对 看是否存在,这里的比对就会用到查询操作,所以我们上面的sql语句中就应该是select * 查询managers表中所有信息;
26行: 是stmt对象调用了他含有的一个方法executeQuery(sql),进行查询操作 参数是条sql语句,返回的是刚刚说的那个结果集ResultSet,这里是查询嘛。如果我们还想要执行插入操作,那么我再创一个prepareStatement对象(放入SQL的插入语句):
这里的?是占位符,对应的是表中的字段
当要插入时用pstmt去调用setString方法,这里这个索引1是对应的上面的第一个占位符,name是一个字符串对象
29行: 这里的循环条件是rs.next(),他是个游标并且在遍历,每调用一次 游标就会往后一位。在下面的30行中会用rs.去调用getString("name")方法,是去获取到遍历到当前这一行的name字段,用来和用户输入的进行equals比较。
其他就是一些输入的逻辑判断,在登录成功后,记得关闭刚刚创建的几个对象(6163行)。其他功能模块也大都类似
//登录: debug完成 √
private static void login() {
try {
Scanner sc = new Scanner(System.in);
boolean flag1 = false; //用于表示登录的用户名是否注册过
//(1)对象参数传递
Manager m = new Manager(); //m为登录时 用户输入的一个临时对象
System.out.println("请输入用户名:");
String name = sc.nextLine();
m.setUsername(name);
System.out.println("请输入密码:");
String userPassword = sc.nextLine();
m.setPassword(userPassword);
String randomNumber1 = checkNumber();
System.out.println("验证码为:"+randomNumber1);
//获取数据库连接
Connection conn = DriverManager.getConnection(url, username, password);
Statement stmt = conn.createStatement();//获取操作数据库的对象
String sql = "select * from managers";
ResultSet rs1 = stmt.executeQuery(sql);
while (rs1.next()) {
if (m.getUsername().equals(rs1.getString("name"))) {
System.out.println("账号存在");
flag1 = true;
break;
}
}
if (flag1 == false) {
System.out.println("用户名未注册,请先注册!");
rs1.close();
stmt.close();
conn.close();
return;
}
//已注册:
if(flag1 == true){
//判断验证码是否正确
int count = 3;//验证码输入错误次数
loop2:while(true){
System.out.println("请输入验证码:");
String randomNumber2 = sc.nextLine();
if(randomNumber1.equalsIgnoreCase(randomNumber2)){ //若验证码输入正确 继续判断用户名和密码是否正确
//根据用户去找密码 看是否与输入的密码相同
System.out.println("验证码正确");
String sql2 = "select * from managers";
ResultSet rs2 = stmt.executeQuery(sql2);
while(rs2.next()){
if(rs2.getString("name").equals(m.getUsername())){//如果找到了此用户名 根据当前的i 去找密码 进行比较
if(rs2.getString("password").equals(m.getPassword())){ //如果密码也相同 则登录成功
System.out.println("登录成功!");
rs1.close();
stmt.close();
conn.close();
//创建对象调用方法,启动超市管理系统!
GoodsTest st = new GoodsTest();
st.startGoodsTest();
break loop2;
}else{
System.out.println("密码错误!");
count--;
System.out.println("你还有"+count+"次机会!");
System.out.println("请再次输入密码");
String newPassword = sc.next();
m.setPassword(newPassword);
break;
}
}
}
}else{
System.out.println("验证码有误,请重新输入");
}
if(count == 1) {
System.out.println("机会已用完!");
break;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
还有每次进行修改之后都记得去更新一下executeUpdate():
第三部分 JDBC的弊端
在上面详细的过了一遍login方法,我们还有forgetPassword、register等方法,那我们可以发现我们在每个单独的方法中 每次都要去连接数据库,结束后又断开数据库。频繁的连接断开,会导致 资源浪费、性能降低!所以JDBC其实有很多的弊端:
原生的JDBC的存在的弊端:
①代码量很大,注册驱动、获取连接 在项目开发中是比较容易变动的,特别是获取连接 在开发时会连接开发数据库,在测试时会连接测试数据库,在生产阶段会连接生产数据库,url、username、password都会变!
而这部分都是被写死在代码中(也称为硬代码),一旦变化,就要重新编译,打包之后才能运行。
②在封装解析结果时,要一个字段一个字段的解析,还要考虑字段类型该调用什么方法,字段一多就愈发的繁琐。
③在执行SQL语句前,先要获取连接,sql语句执行完毕之后,又要关闭连接;在项目中去频繁的获取连接会导致 资源浪费、性能降低!
我们再来对比在Mybatis中是如何解决这些问题的!!
①首先关于硬编码,Mybatis是将数据库连接的四要素直接配置在application.properties中,可以直接在它里面操作就好~
②在解析结果时,Mybatis它会自动的将查询的结果封装到这个集合当中,查询返回的每一条记录都会封装为一个user对象,所有的user对象又会封装到一个List集合中,整个过程自动化进行
③关于频繁获取连接、释放连接 浪费资源问题,Mybatis中,在application.properties中每条配置语句前面都有spring.datasource前缀,springboot底层就会自动的采用数据库连接池技术来统一管理和分配这些连接
其实指的就是JDBC中的Connection对象那一行,有了连接池之后,每一次在执行sql语句的时候,我们只需要从连接池中获取一个连接去执行sql语句,完毕后,再将这个连接还给连接池,那这样就可以做到连接的复用,后面会再讲数据库连接池技术。
没有对比就没有伤害,Mybatis完胜!在我们使用springboot整合mybatis进行数据库操作时,我们主要关注两点:一个就是在application.properties中关于mybatis的相关配置;另一个方面就是mapper接口以及我们所定义的SQL语句~