大家可以关注一下我的博客 我的博客所有随笔都是我从基础开始学习java的所有知识点
1. Jdbc概述
问题:实际开发中,不可能用工具或者命令行操作数据库,数据库表中的数据最终要使用Java程序来操作,那么Java中如何操作数据库中的数据呢?
答 : 在Java语言中,有一个专门连接数据库的规范(JDBC),专门负责连接数据库进行数据操作的规范
JDBC只是SUN编写的一堆接口(规范的体现),SUN公司自己并没有实现
问题 : 为什么SUN只定义一个JDBC规范,而不实现呢?
答 : 因为市面上的数据库很多,每个数据库内部接口不会向外暴露,而且即便是暴露让SUN去实现,市面上很多数据库全部要SUN来实现不现实
实际中哪个数据库需要支持JAVA语言,就需要自己实现Java的JDBC规范,因为实现了JDBC很多接口,那么就会有很多实现类,而很多实现类在java中会使用一个专门的包封装起来,叫做jar包(在JDBC中叫做驱动包),各大数据库产商实现JDBC规范以后都会把他们jar包放在官网上以供开发者下载使用
JDBC:(Java DataBase Connectivity):
是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。
JDBC规范对应的api包
案例使用JDBC操作MySQL数据库:
1. 创建普通java项目
2. 在项目下面新建一个lib目录(new键--》folder)
3. 将MySQL驱动包拷贝到项目中并添加依赖(build path--》add to build path)
4. 开始写代码
DDL创建表:
package jdbc; //连接使用oracle数据库 import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; import org.junit.Test; public class Test01 { /** * Java中单元测试方法的 创建 * * 在空白处 写 test,使用快捷键 alt+/ 提示,选择 junit4 * 会自动补全 junit4单元测试的方法 * 在方法上面有一个注解,默认报错的 * 因为:单元测试是一个框架,默认eclipse以及集成了,用户把鼠标放置在 注解上面,按提示导入junit4 依赖即可 * 单元测试方法和main方法区别 * junit单元测试方法在一个类中可以有多个方法,每个一个方法可以独立运行 * main 主方法一个类中只能有一个方法,不太方便多个功能的测试 * * 单元测试方法的运行,光标放置在单元测试方法上面,点击数据右键 【run as ->junit test】 * 绿条:表示成功 * 红条:表示程序可能异常 */ @Test public void testName1() throws Exception { //创建表操作:要执行的sql代码 String sql="create table t_student(sid number(4) constraint pk_sid primary key,name varchar2(20))"; //1,加载注册驱动 Class.forName("oracle.jdbc.OracleDriver"); /*加载注册驱动.(mysql的) 就是把驱动中的Driver字节码加载到JVM中. Class.forName("com.mysql.jdbc.Driver"); 为什么这句话就可以加载注册驱动? 第一步:把com.mysql.jdbc.Driver.class这份字节码加载到JVM中. 第二步:当一份字节码被加载进JVM,马上就会执行该字节码中的静态代码块. 第三步:该静态代码中,就在完成,先创建驱动对象,再注册. * */ //2,获取数据库连接("jdbc:oracle:thin:@127.0.0.1:1521:数据库名","账号","密码") Connection conn= DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl","scott","tiger"); /*jdbc:mysql://localhost:3306/dbName jdbc:mysql:// :连接MySQL数据库的协议,不同数据库协议不一样 localhost:3306 :数据库软件的主机和端口 dbName : 具体要连接数据库 验证已经获取连接:可以在MySQL控制台,使用命令:show processlist; 查看MySQL运行进程. * */ //3,创建语句对象(用于执行SQL语句的对象) Statement c = conn.createStatement(); //4, 执行SQL语句 c.executeUpdate(sql); //5,释放资源(先开后关) c.close(); conn.close(); } }
package jdbc; //连接使用mysql数据库 import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; import org.junit.Test; public class Test02 { @Test public void testName1() throws Exception { //创建一个学生表 //创建表的mysql操作:要执行的sql代码 String sql="create table t_student(id int primary key auto_increment,name varchar(50),age int)"; //1.加载注册驱动 Class.forName("com.mysql.jdbc.Driver"); //2.获取数据库连接对象 Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/lin01", "root", "root"); //3.创建语句对象(用于执行SQL语句) Statement st=conn.createStatement(); //4.执行SQL语句 st.executeUpdate(sql); //5.释放资源(先开后关) st.close(); conn.close(); } }
DML:表的增删改:
package jdbc; //连接使用mysql数据库 import static org.junit.Assert.*; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; import org.junit.Test; public class Test02 { @Test public void testName1() throws Exception { //DML 增: //创建表的mysql操作:要执行的sql代码 String sql=("insert into t_student(name,age) values ('张三',20)"); //1.加载注册驱动 Class.forName("com.mysql.jdbc.Driver"); //2.获取数据库连接对象 Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/lin01", "root", "root"); //3.创建语句对象(用于执行SQL语句) Statement st=conn.createStatement(); //4.执行SQL语句 st.executeUpdate(sql); //5.释放资源(先开后关) st.close(); conn.close(); } public void testName2() throws Exception{ //DML 删: String sql=("delete from t_student where id=2"); Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/lin01", "root", "root"); Statement st=conn.createStatement(); st.executeUpdate(sql); st.close(); conn.close(); } @Test public void testName3() throws Exception { //DML 改: String st="update t_student set name='李四',age=15 where id=1"; Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/lin01", "root", "root"); Statement cr= conn.createStatement(); cr.executeUpdate(st); cr.close(); conn.close(); } }
DQL表的查询:
package jdbc; //学生类 public class Student { private int id ; private String name; private Integer age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Student(int id, String name, Integer age) { super(); this.id = id; this.name = name; this.age = age; } public Student() { super(); } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", age=" + age + "]"; } }
package jdbc; //连接使用mysql数据库 import static org.junit.Assert.*; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import org.junit.Test; public class Test02 { @Test public void testName1() throws Exception { //多行查询 String str="select * from t_student"; Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/lin01", "root", "root"); Statement cr = conn.createStatement(); ResultSet ex = cr.executeQuery(str); //创建一个学生类 //申明一个list集合,封装一个个学生对象 List<Student> stu = new ArrayList<Student>(); while(ex.next()){ //1.通过列的位置获取对应的数据 从1开始(如果不知道类型就用Object) Object id = ex.getObject(1); Object name = ex.getObject(2); Object age = ex.getObject(3); System.out.println(id+" "+name+" "+age); cr.close(); conn.close(); //2.通过列的名称获取对应的数据((知道类型就用相应的类型) int id1 = ex.getInt("id"); String name1 = ex.getString("name"); int age1 = ex.getInt("age"); System.out.println(id1+" "+name1+" "+age1); cr.close(); conn.close(); //3.将每一行数据封装成一个个Student对象 ////快速生成变量,光标放在 代码末尾, ctrl+1 提示 int id2 = ex.getInt("id"); String name2 = ex.getString("name"); int age2 = ex.getInt("age"); Student student = new Student(id2,name2,age2); stu.add(student); } for (Student student : stu){ System.out.println(student); } ex.close(); cr.close(); conn.close(); } }
package jdbc; //连接使用mysql数据库 import static org.junit.Assert.*; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import org.junit.Test; public class Test02 { @Test public void testName1() throws Exception { //单行查询 String str="select * from t_student where id=7"; Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/lin01", "root", "root"); Statement cr = conn.createStatement(); ResultSet ex = cr.executeQuery(str); List<Student> stu=new ArrayList<Student>(); if(ex.next()){ int id = ex.getInt("id"); String name = ex.getString("name"); int age = ex.getInt("age"); Student stud=new Student(id,name,age); stu.add(stud); } System.out.println(stu); } }
预编译语句对象PreparedStatment
问题 : 我们有了Statment对象可以执行SQL,为什么还要使用PreparedStatment?
优势
- SQL语句结构清晰,参数的设置和SQL语句分离
- 性能更高
- 防止SQL注入
Statement: 表示静态SQL语句对象.
PreparedStatement:Statement的子接口,表示预编译SQL语句对象. 通过占位符(?)来拼SQL.
package jdbc; //连接使用mysql数据库 import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import org.junit.Test; public class Test02 { @Test public void testName1() throws Exception { //使用预编译语句对象执行DML操作 //模板sql语句(增加数据) String sql="insert into t_student(name,age) values(?,?) "; /**删除:String sql = "delete from t_student where id = ?"; * 修改:String sql = "update t_student set name = ?,age=? where id = ?"; */ // 1.加载注册驱动 Class.forName("com.mysql.jdbc.Driver"); // 2.获取数据库连接对象 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/lin01", "root", "root"); // 3.创建预编译语句对象 PreparedStatement pr = conn.prepareStatement(sql); //3.1设置预编译语句对象占位符对应的参数值 pr.setString(1, "maxysh"); pr.setInt(2, 99); // 4.执行SQL语句 (注意:方法不能带sql参数) pr.executeUpdate(); // 5.释放资源 pr.close(); conn.close(); } }
package jdbc; //连接使用mysql数据库 import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import org.junit.Test; public class Test02 { @Test public void testName1() throws Exception { //使用预编译语句对象执行DML操作 //模板sql语句(查询数据) String sql="select * from t_student "; // 1.加载注册驱动 Class.forName("com.mysql.jdbc.Driver"); // 2.获取数据库连接对象 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/lin01", "root", "root"); // 3.创建预编译语句对象 PreparedStatement pr = conn.prepareStatement(sql); // 4.执行SQL语句 (注意:方法不能带sql参数) ResultSet ex = pr.executeQuery(); //申明一个list集合,封装一个个学生对象 List<Student> students = new ArrayList<Student>(); while(ex.next()){ int id = ex.getInt("id"); String name = ex.getString("name"); int age = ex.getInt("age"); Student stu=new Student(id,name,age); students.add(stu); } System.out.println(students); // 5.释放资源 ex.close(); pr.close(); conn.close(); } }
JavaWeb开发的分层设计-三层架构
DAO层设计
实际开发中,JavaWeb开发代码一般分为三层,分层结构是JavaWeb开发中的一种设计思想,这样会让我们开发层次分明,每一层只要完成对应的功能即可,使得项目便于开发和维护
1 . Web层/表现层 : 主要接受前台浏览器用户的参数,给浏览器响应数据等等
2.Service层/业务成/服务层:主要处理业务功能,日志,权限,事物,等等
3.DAO层/持久层 :专门负责和数据库交互,数据处理相关代码
DAO : Data Access Object 数据访问对象
实际开发中 : 用户请求到-Web层--->Service层-->DAO层
使用DAO以后代码的以及包的设计结构
开发中如果使用的分层,编写的包和类名接口名等等都是有固定规则,不能随便瞎写
DAO层接口包命名
公司域名倒写+项目名称/模块名称+dao 如 : cn.sxt.crm.dao
DAO层实现类包命名
公司域名倒写+项目名称/模块名称+dao+impl 如 : cn.sxt.crm.dao.impl
DAO层操作对应表的接口命名
对应表的名称 + Dao/DAO 如 : StudentDao/DAO , TeacherDao/DAO
DAO层操作对应表的实现类命名
对应表的名称 + Dao/DAOImpl 如 : StudentDaoImpl/DAOImpl , TeacherDaoImpl/DAOImpl
数据表对应的Java类domain/pojo包命名
POJO(Plain Ordinary Java Object)简单的Java对象
domian : 域对象
公司域名倒写+项目名称/模块名称+domain/pojo 如 : cn.sxt.crm.domain
对应的测试包命名
公司域名倒写+项目名称/模块名称+test 如 : cn.sxt.crm.test
项目的工具类包命名
公司域名倒写+项目名称/模块名称+util/utils 如 : cn.sxt.crm.util/utils
package cn.sxt.crm.test; import java.io.InputStream; import java.util.Properties; import org.junit.Test; /*new --->file * ClassLoader 类加载器 * ClassLoader :可以从项目的类路径下面读取对应的配置文件返回一个输入流 * ClassLoader 在程序运行的时候JVM已经为每一个项目都创建了一个,我们开发者只需要获取即可 * 获取类加载器方式 * 1、使用当前线程 * ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); * 2、通过某一类的字节码实例也可以获取 * ClassLoader classLoader = PropertiesTest.class.getClassLoader(); */ //ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); //使用类加载器获取项目 类路径下面的文件 //InputStream inputStream = classLoader.getResourceAsStream("db.properties"); /* * Properties 是Map集合下面的一个 专门用于读取配置文件的对象 * 可以读取当前类路径下面的 xxx.properites类型的配置文件 * * xxx.properites的内容必须是key=value 键值对的数据 */ public class PropertiesTest { @Test public void test1() throws Exception { //1.使用当前线程可以获取类加载器 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); //2.使用类加载器读取db.properties配置文件 InputStream in = classLoader.getResourceAsStream("dp.properties"); //3.创建Properties对象(专门读取xxx.properties配置文件中的内容,本质就是Map集合,数据结构key--->value) Properties p = new Properties(); //4.加载配置文件 p.load(in); System.out.println(p); //5.获取单个指定key的值 String str1=p.getProperty("str1"); String str2=p.getProperty("str2"); String str3=p.getProperty("str3"); String str4=p.getProperty("str4"); System.out.println(str1); } }
package cn.sxt.crm.test; import static org.junit.Assert.*; import java.io.InputStream; import java.sql.Connection; import java.util.Properties; import javax.sql.DataSource; import org.junit.Test; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; //Druid连接池的使用 public class DateSourceTest { @Test//直接手动创建连接池对象 public void testName1() throws Exception { //1.创建druid连接池对象 DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3306/lin01"); ds.setUsername("root"); ds.setPassword("root"); //设置最大连接数 ds.setMaxActive(10); Connection conn = ds.getConnection(); System.out.println(conn); } //使用Druid工厂对象读取配置文件来创建连接池对象 @Test public void testName() throws Exception { //获取类加载器 ClassLoader classLoader=Thread.currentThread().getContextClassLoader(); InputStream in=classLoader.getResourceAsStream("dp.properties"); Properties properties=new Properties(); properties.load(in); //使用工厂创建连接池对象 DataSource ds=DruidDataSourceFactory.createDataSource(properties ); Connection conn = ds.getConnection(); System.out.println(conn); } }
str1=com.mysql.jdbc.Driver str2=jdbc:mysql://localhost:3306/lin01 str3=root str4=root maxActive=10
-----------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------
package cn.sxt.crm.dao; import java.util.List; import cn.sxt.crm.pojo.Student; public interface StudentDao { /** * 插入方法 * @param stu 封装有学生信息的Student对象(数据库自增id,开发者不需要传id) * @return 受影响的行数 */ int insert(Student stu);//增方法 /** * 根据主键删除数据 * @param id 主键id的值 * @return 受影响的行数 */ int delete(Integer id); /** * 修改操作 * @param stu 带有id值的Student对象(修改根据主键id值修改) * @return 受影响的行数 */ int update(Student stu); /** * 单行查询 * @param id 主键id * @return 单行数据封装的对象 */ Student selectByPrimaryKey(Integer id); /** * 多行查询 * @return 封装有一个个Student对象的集合 */ List<Student> selectList(); }
package cn.sxt.crm.dao.impl; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import cn.sxt.crm.dao.StudentDao; import cn.sxt.crm.pojo.Student; import cn.sxt.crm.util.utils; public class StudentDaoImpl implements StudentDao { @Override public int insert(Student stu) { String sql="insert into t_student(name,age)values(?,?)"; Connection conn=null; PreparedStatement pr=null; try { conn =utils.getConnection(); pr = conn.prepareStatement(sql); pr.setString(1,stu.getName()); pr.setInt(2, stu.getAge()); int row=pr.executeUpdate(); return row; } catch (Exception e) { e.printStackTrace(); }finally{ utils.close(conn, pr, null); } return 0; } @Override public int delete(Integer id) { String sql="delete from t_student where id=?"; Connection conn=null; PreparedStatement pr=null; try { conn = utils.getConnection(); pr = conn.prepareStatement(sql); pr.setInt(1,id); int row=pr.executeUpdate(); return row; } catch (Exception e) { e.printStackTrace(); }finally{ utils.close(conn, pr, null); } return 0; } @Override public int update(Student stu) { String sql="update t_student set name=?,age=? where id=?"; Connection conn=null; PreparedStatement pr=null; try { conn =utils.getConnection(); pr = conn.prepareStatement(sql); pr.setString(1,stu.getName()); pr.setInt(2, stu.getAge()); pr.setInt(3, stu.getId()); int row=pr.executeUpdate(); return row; } catch (Exception e) { e.printStackTrace(); }finally{ utils.close(conn, pr, null); } return 0; } @Override public Student selectByPrimaryKey(Integer id) { String sql="select * from t_student where id=?"; Connection conn=null; PreparedStatement pr=null; ResultSet ex=null; try { conn = utils.getConnection(); pr = conn.prepareStatement(sql); pr.setInt(1,id); ex = pr.executeQuery(); while(ex.next()){ String name=ex.getString("name"); int age=ex.getInt("age"); // 封装Student对象 Student stu = new Student(id, name, age); //返回Student对象 return stu; } } catch (Exception e) { e.printStackTrace(); }finally{ utils.close(conn, pr, ex); } return null; } @Override public List<Student> selectList() { List<Student> student= new ArrayList<Student>(); String sql="select * from t_student"; Connection conn=null; PreparedStatement pr=null; ResultSet ex=null; try { conn =utils.getConnection(); pr = conn.prepareStatement(sql); ex = pr.executeQuery(); while(ex.next()){ int id=ex.getInt("id"); String name=ex.getString("name"); int age=ex.getInt("age"); // 封装Student对象 Student stu = new Student(id, name, age); // 学生对象添加到集合中 student.add(stu); } } catch (Exception e) { e.printStackTrace(); }finally{ utils.close(conn, pr, ex); } return student; } }
package cn.sxt.crm.pojo; public class Student { private Integer id; private String name; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Student(Integer id, String name, Integer age) { super(); this.id = id; this.name = name; this.age = age; } public Student() { super(); } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", age=" + age + "]"; } }
package cn.sxt.crm.test; import java.util.List; import org.junit.Test; import cn.sxt.crm.dao.StudentDao; import cn.sxt.crm.dao.impl.StudentDaoImpl; import cn.sxt.crm.pojo.Student; public class StudentDaoTest { private StudentDao dao=new StudentDaoImpl(); @Test public void testInsert() { Student stu=new Student(null, "叶孤城", 30); int row=dao.insert(stu); System.out.println(row); } @Test public void testDelete() { int row=dao.delete(10); System.out.println(row); } @Test public void testUpdate() { Student stu=new Student(9, "叶孤城", 30); int row=dao.update(stu); System.out.println(row); } @Test public void testSelectByPrimaryKey() { Student stu = dao.selectByPrimaryKey(3); System.out.println(stu); } @Test public void testSelectList() { List<Student> students = dao.selectList(); System.out.println(students); } }
package cn.sxt.crm.util; import java.io.InputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Properties; import javax.sql.DataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; public class utils { // 创建读取配置文件的配置对象 private static Properties p=new Properties(); //连接池对象 private static DataSource da; static { try { ClassLoader classLoader=Thread.currentThread().getContextClassLoader(); InputStream inputStream=classLoader.getResourceAsStream("dp.properties"); p.load(inputStream); //创建连接池对象 da= DruidDataSourceFactory.createDataSource(p); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection(){ try { Connection conn = da.getConnection(); return conn; } catch (Exception e) { throw new RuntimeException("连接失败"); } } public static void close(Connection conn,PreparedStatement pr,ResultSet ex){ try { if(ex!=null){ex.close();} } catch (SQLException e1) { e1.printStackTrace(); }finally{ try { if(pr!=null){ pr.close(); } } catch (SQLException e) { e.printStackTrace(); }finally{ try { if(conn!=null){ conn.close(); } } catch (SQLException e) { e.printStackTrace(); } }} } }
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/lin01
username=root
password=root
maxActive=1
配置必须按规定命名,