JAVA学习日志2-5(JDBC)
JDBC
jdbc的全称是 java database connection,是java和数据库连接的桥梁。jdbc是java提供的一个接口或者是规范,具体的实现是由各个数据库厂商来完成的。所有不同的数据库需要不同的jabc驱动包。
-
jabc中一些常用的接口和类
接口或类 DriverManager(类) 驱动管理类,用于注册驱动 Connection(接口) 连接对象,用于连接数据库 Statemnet(接口) 执行sql的对象,用于发送sql给数据库 ResultSet(接口) 结果集,用于获取获取查询结果 -
jdbc连接数据的基本的步骤
1.加载驱动
2.获取连接对象
3.得到执行sql的对象
4.获取结果集
5.关闭资源 -
jdbc 连接mysql数据库
- 下载用于mysql的驱动包,mysql官网下载:https://dev.mysql.com/downloads/connector/j/5.1.html
- 为jar包添加依赖(Idea)
新建一个lib目录用来存放jar包,然后添加依赖
(可以在添加一个juint的jar包,可以使 public void 的方法不用去主函数中就可以直接执行,但要在方法前添加注解 @Test) - 依赖添加成功后,就可以通过下面的代码连接了
//通过反射加载驱动
Class.forName("com.mysql.jdbc.Driver");
/*通过连接管理对象获取对象,其中 jdbc:使用jdbc来连接数据(主协议),mysql:连接mysql数据库
(子协议),localhost:3306 主机地址及端口号,mydb2 数据库名,characterEncoding=utf-8 表示
设置其编码格式,后面的两个root分别为数据库的用户名和密码*/
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb2?characterEncoding=utf-8", "root", "root");
//通过连接对象 获取到执行sql 的对象
Statement sta = conn.createStatement();
//执行sql语句 增 删 改 使用.executeUpdata(sql) 返回的是int类型的数据,表示影响的行数
String sql = " insert into tab1 values(2,'lili')";
sta.executeUpdate(sql);
//执行sql语句 查询 时使用.executeQuery(sql) 返回的是ResultSet类型的数据,表示查询结果,需要遍历获取到每个值
String sql = "select * from stu;";
ResultSet rs = sta.executeQuery(sql);
while(rs.next()){
//获取当前行的第一列元素,也可以通过字段名来获取
//String sid = rs.getString("sid");
String sid = rs.getString(1);
String sname = rs.getString(2);
int age = rs.getInt(3);
System.out.println(sid+"\t"+sname+"\t"+age);
}
PrepareStatement 对象
使用Statement 对象执行sql语句当sql语句有具体值传递是,需要用到字符串的拼接
Scanner sc = new Scanner(System.in);
String str = sc.next();
int num = sc.nextInt();
Statement sta = conn.createStatement();
String sql = "select * from stu where sid='"+str+"' and age ="+num;
ResultSet rs= sta.executeQuery(sql);
这样虽然可以找到正确的数据,但存在sql注入的问题,如 str赋值为 1’or’1’=‘1’# ,num赋值为1,则实际执行的sql语句是
select * from stu where sid='1'or'1'='1'#' and age =1
#号后面的内容sql语句都判断为了注释,前半部分中无论sid是否有1这样的值,‘1’='1’是恒成立的,通过or连接后这条sql语句就会正常执行了,如果这个方法使用在一个登陆验证是非常危险的。
PrepareStatement 不拼接字符串,动态参数可以使用占位符来进行替换这样就消除的sql注入。(PrepareStatement 是 Statement的子类)
String sql = "insert into stu values (?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
//把第一个占位符的值设置成"S_1022"
ps.setString(1,"S_1022");
ps.setString(2,"luiui");
ps.setInt(3,45);
ps.setString(4,"male");
//执行时,不需要在传递sql语句了
ps.executeUpdate();
jdbc工具类的封装
每次向数据库发生sql语句时,都需要加载驱动,建立连接,创建执行sql的对象,执行sql这其中有很多公共的部分,可以进行抽取。
-
加载驱动和建立连接的封装
驱动加载可能会因为数据库的不同加载不同的驱动,建立链接时可能连接的数据库不同url也就不同,所以可以把这些信息放在配置文件里。返回Connection类型。文件存储的内容:
文件读取的工具类(单例设计模式)(读取时按key取值):public class PropertiesUtils { private static PropertiesUtils proU; private Properties pro; private PropertiesUtils(){ pro = new Properties(); try { FileInputStream fis = new FileInputStream("database.properties"); pro.load(fis); } catch (IOException e) { e.printStackTrace(); } } public static PropertiesUtils getInstanceOf(){ if(proU==null){ synchronized (PropertiesUtils.class){ if(proU==null){ proU = new PropertiesUtils(); } } } return proU; } public String getValue(String key){ String value = pro.getProperty(key); return value; } }
BaseDAO类里的封装
public Connection getconn(){ Connection conn = null; try { Class.forName(PropertiesUtils.getInstanceOf().getValue("jdbc.driver")); conn = DriverManager.getConnection(PropertiesUtils.getInstanceOf().getValue("jdbc.url"),PropertiesUtils.getInstanceOf().getValue("jdbc.username"),PropertiesUtils.getInstanceOf().getValue("jdbc.password")); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return conn; }
-
执行sql对象的封装
执行sql的对象可以分为两大类,1.增 删 改 操作的sql返回的是int类型,使用.executeUpdate() 2.查询 的sql 返回ResultSet类型,使用.executeQuery().增 删 改的封装,封装成一个方法后需要两个参数,一个参数是带有占位符的sql语句,一个参数是每个占位符的具体值,每个具体值肯不同所有采用object数组
public int update(String sql,Object[] obj){ int num = -1; Connection conn = getconn(); PreparedStatement ps = null; try { ps = conn.prepareStatement(sql); //给每个占位符赋值 if(obj!=null&&obj.length>0){ for(int i=0;i<obj.length;i++){ ps.setObject(i+1,obj[i]); } } num = ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { close(null,ps,conn); } return num; }
查询 的封装,查询结果可以与实体类对应,这里是Pet类,返回list对象
public List query(String sql,Object[] obj){ List<Pet> list = new ArrayList<Pet>(); Connection conn = getconn(); PreparedStatement ps = null; ResultSet rs = null; try { ps= conn.prepareStatement(sql); if(obj !=null&&obj.length>0){ for(int i=0;i<obj.length;i++){ ps.setObject(i+1,obj[i]); } } rs = ps.executeQuery(); while(rs.next()){ int id = rs.getInt("id"); String name= rs.getString("name"); int health = rs.getInt("health"); int love = rs.getInt("love"); String strain = rs.getString("strain"); Pet pet = new Pet(id,name,health,love,strain); list.add(pet); } } catch (SQLException e) { e.printStackTrace(); }finally { close(rs,ps,conn); } return list; }
-
关闭资源的封装
public void close(ResultSet rs,PreparedStatement ps,Connection conn){ try { if(rs!=null) rs.close(); if(ps!=null) ps.close(); if(conn!=null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } }
BaseDAO工具类的调用
@Test
public void updatePetById(){
String sql = "update pet set name=? where id=?";
Object[] obj = new Object[]{"zhuzi", 1};
BaseDAO base = new BaseDAO();
int num = base.update(sql,obj);
if(num>0){
System.out.println("修改成功!");
}
}
@Test
public void find(){
String sql = "select * from pet where name like ?";
Object[] obj = new Object[]{"%a%"};
BaseDAO base = new BaseDAO();
List<Pet> list = base.query(sql,obj);
for(Pet temp : list){
System.out.println(temp);
}
}