JDBC 的基本概念总数(包括Spring 模板和数据库连接池)

JDBC

  1. JDBC基本概念
  2. 快速入门
  3. 对JDBC中各个接口和类的详解

JDBC的基本概念

1. 概念:Java Database Connectivity  Java -> 数据库连接(Java语言操作数据库)
	* JDBC的本质,由官方定义了一套操作所有关系型数据库的规则,即接口。
	* 各个数据库厂商提体的具体的实现类,这个具体的实现类被称为数据库驱动。
2.快速入门
		* 步骤:
				1.导入驱动Java包
					1.1复制jar到项目的lib目录下
					1.2右键-->Add As Library
				2.注册驱动
					2.1 Class.forname("com.mysql.jdbc.Driver");//注册
				3.获取数据库的连接对象(Connection对象)
				4.获取sql语句的执行对象(statement)
				5.执行sql,接受返回结果
				6.处理返回结果
				7.释放资源
			
		*代码实现:public static void main(String[] args) throws SQLException {  
			    //导入驱动的jar包  
				  Statement statm = null;  
				  Connection conn = null;  
				 try {  
				        //2.注册驱动包  
				  Class.forName("com.mysql.jdbc.Driver");  
				  
				  //3.获取连接  
				  conn = DriverManager.getConnection("jdbc:mysql://localhost:3307/mysql2","root","123456");  
				  
				  //4.定义sql语句  
				  String sql = "update user set loginName='zhangsan',lologinPwd='123456' where loginName = 'zhangsan'";  
				  
				  //5.获取执行sql对象的statement  
				  statm = conn.createStatement();  
				  
				  //6.执行sql  
				  statm.executeUpdate(sql);  
				  
				  } catch (ClassNotFoundException e) {  
				        e.printStackTrace();  
				  } finally {  
				        //7.释放资源  
				  if(statm != null){  
				            statm.close();  
				  }  
				        if(conn != null){  
				            conn.close();  
				  }  
				    }  
				}
3.详解各个对象
	3.1	DriverManager(类):驱动管理对象(告诉程序性我们要使用,哪个数据库的驱动包)
		*功能:
			1.注册驱动->static void registerDriver(Driver driver)->注册-->给定的驱动程序 DriverManager.
						Class.forName("com.mysql.jdbc.Driver");这个反射获取了com.mysql.jdbc.Driver这个路劲下的Driver类,并且在Driver类中的静态代码块中执行registerDriver方法,注册了驱动信息。
			#在Driver类中包含了一个静态代码块,在没有对象的前提下也可以执行,
					static {

					try {

								java.sql.DriverManager.registerDriver(new  Driver());   //这个就是利用放射调用Driver类的时候,这里的静态代码区会被执行,也就是执行了这个方法注册了驱动

								} catch (SQLException  E) {

								throw  new  RuntimeException("Can't register driver!");

					}

					}

	注意:mysql 5之后的驱动jar包可以忽略。
				
		
			2.获取数据库连接对象
				*方法:->Driver.getConnection(String url,String user, String password);
				*参数:
					*url;指定 连接的路径
						*语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
							 *例子:jdbc:mysql://localhost:3307//mysql2
							 *细节:当连接的是本机的mysql服务器,并且mysql服务器默认端口是3306的时候,则url可以简写为jdbc:mysql:///mysql2
	3.2	Connection(接口):	数据库连接对象
		*功能:
			1.获取执行sql的对象(Statement,PrePareStatement)
				    *Statement createStatement()
				    *PreparedStatement prepareStatement(String sql);
			2.管理事物:
					*开启事物
							void setAutoCommit(boolean autoCommit);当传入的参数为false的时候,,关闭自动提交,就是开启事物。
					*提交事物
							void commit();
					*回滚事物	    
							void rollback();
	3.3 Statement(接口,执行静态的sql语句,静态的sql):执行sql的对象
			1.执行sql
				*boolean execute(String sql):可以执行任意的sql  	@了解
				*int executeUpdate(String sql):执行dml(insert,update,delete)语句;ddl(create,alter,drop)语句  @ddl语句一般在sql中执行,不在java中执行。
					返回值的是,sql语句影响的行数(具体改变了多少行),用于判断是否执行成功。
				*ResultSet executeQuery(String sql):执行dql(select)语句,
					返回值:返回结果集对象(ResultSet)
			2.练习:	
				1.account表 添加一条记录
				2.account表 修改记录
				3.account表 删除一条记录		
	3.4 ResultSet:结果集对象,对返回集进行处理
				*boolean next():游标向下移动一行(每执行一次next(),光标向下移动一行,移动后的那一行有数据返回true,否则返回false,类似迭代器)
				*xxx getxxx(参数):获取数据
					*返回值:xxx是数据类型, 如:String getString()
					*参数:(有重载的方法)
						1. int类型参数:代表列的编号,从1开始的(特殊)  如:getString(1)
						2. String类型参数:代表列的字段名。 如:getInt("id");
					*注意:
						*使用步骤
							1.游标向下移动一行
							2.判断是否有数据(关键)
							3.获取数据
					*练习:
						*查询emp表的数据,将其封装为对象,然后装载集合,然后打印,返回。(提示一张表可以类比成一个类,一条记录类比成一个对象)		
							1.定义一个emp类
							2.定义一个方法public List<emp> findAll();
							3.实现方法 select * from emp;
	3.5 PreparedStatement(接口,执行预编译的sql语句,动态的sql):执行sql对象,更加强大,继承自statement
				*由于在拼接sql时,有一些sql的关键字参与字符串的拼接,会造成安全问题
				 1.为解决sql注入问题,提供了PreparedStatement对象来解决
				 2.预编译的sql:参数使用?作为占位符
				 3.步骤:
						 1.导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
						 2.注册驱动
						 3.获取数据库连接对象Connection
						 4.定义sql
							  *注意:sql的参数使用:?作为占位符。如:select * from user where username = ? and password = ?;
						 5.获取sql执行对象(获取的是PreparedStatement对象,这个与createdStatement()不同,prepareStatement(String sql)这个方法需要将带?的预编译的sql字符串作为参数传入)
						 6.给?赋值
							 使用prepareStatement下的方法,setxxx(参数1,参数2)
								*参数1:赋值第一个?
								*参数2:赋值第二个?
						 7.执行sql,接受返回结果,不需要在传入sql语句
						 8.处理结果
						 9.释放资源
				*注意:后期都会使用PerparedStatement对象来完成增删改查的所有操作
						1.可以防止sql注入
						2.效率更高		 
4.抽取JDBC的工具类
	*目的:简化书写
	*分析:
			1.抽取一个方法获取连接对象 
			2.注册一个方法获取连接对象
					*需求:	想要动态配置ip,端口和数据库,又不想要传参
				    *解决方案:使用配置文件
						jdbc.properties
							url=
							user=
							password=
						
						*从jdbc.properties文件中相关字符串的办法,通过Properties对象的load(new DileReader("路径"))方法
							路径的方法可以是动态的获取路径信息,利用类中本身含有的方法获取ClassLoader的对象,再利用ClassLoader类的方法getResource("文件名字"),返回一个URL对象;再利用URL对象下的getPath(),返回路径的字符串。
							*`static{  
							    try {  
										        //读取资源文件,获取值  
									  //1.创建一个properties集合类  
									  Properties pro = new Properties();  
									  //获取src路径下的文件方式--->ClassLoader类加载器  
									  ClassLoader classLoader = JDBCUtils.class.getClassLoader();  
									  URL res = classLoader.getResource("jdbc.properties");  
									  String path = res.getPath();  
									  //2.加载文件  
									  //pro.load(new FileReader("./src/jdbc.properties"));  
									  pro.load(new FileReader(path));  
									  url = pro.getProperty("url");  
									  user = pro.getProperty("user");  
									  password = pro.getProperty("password");  
									  driver = pro.getProperty("driver");  
									  } catch (IOException e) {  
									        e.printStackTrace();  
									  }  
									}`	
					
			*练习:
				*需求:
					1.通过键盘录入用户名和密码
					2.判断用户是否登录成功	
						*select * from user where username = '+userName+' and password = '+password+';
						*如果这个sql有查询结果,则成功,反之则失败。
							
				*步骤
						1.创建登录表 create table user();
						2.将登录界面打包封装成一个方法
						3.利用工具类,开始注册创建驱动和获得连接 
								*Connection conn = JDBCUtil.getConnection();
						4.写sql命令
						5.获取sql命令的执行对象,Statement
						6.执行命令,获取ResultSet结果集,
						7.返回判断结果
											
			   *程序bug
					   *sql注入(在拼接sql时,有一些sql的关键字参与字符串的拼接,会造成安全问题)
						   1.输入用户随便,输入的密码:a' or 'a' = 'a
						   2.sql: 随便输入用户名:faaf, 得到的sql语句:select * from user where username = 'faaf' and password = 'a' or 'a' = 'a'(这里由于字符串在拼接的时候出现了问题)
								  解释:目的是将a' or 'a' ='a 视为一个字符串来进行判断 ,
										  但是在实际执行的时候出现了 数据库将其视为了 
										  username = 'faaf' 
										  and
										  password = 'a'
										  or
										  'a' = 'a',三种逻辑态的拼接,由于and的优先级更高,先执行and,右边为false ,但是 or右边为恒等式为true,最后结果为true ---> 由于where的右边恒为true,也就select在执行比对时每一行记录都不会被筛除,select会输出所有记录,这种就被称为sql注入;
						   3.解决方法:使用perpareStatement
5.JDBC控制事物
		 1.事物:一个包含多个不做的业务操作。如果这个业务操作被事物管理,则这多个事物要么同时成功,要么同时失败。
		 2.操作:
			 1.开始事物
			 2.提交事物
			 3.回滚事物
		
		 3.使用Connect对象来管理事物
			 *开启事物: setAutoCommit(boolean autoCommit) ,将传入参数false代表事物开启(自动提交关闭)   在执行sql命令之前开启事物
			 *提交事物:commit(); 顺利完成commit
			 *回滚事物:rollback(); 出现异常回滚,在catch{}中使用rollback()

6.数据库连接池--->因为连接(Connection)建立在try  catch中会被频繁的删除,在频繁的建立连接会拖延系统的时间,因此引入了数据库池。
		*概念:其实就是一个容器,存放数据库连接的容器;当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库的时候,从容器中获取连接对象,用户访问完后,将会把连接对象归还给容器。
			  例子:这下所有的服务员被一家公司集中管理,餐馆需要服务员时直接去公司申请,不在需要自己去去找服务员(高效),这样节约了自己找人的成本,因为公司集中化管理给的价格也更低(节约了资源)
		*好处,优点:
			1.节约系统的资源(集中管理连接对象,更资源分配更均匀)
			2.高效(不需要向底层申请,节约时间,申请和返回不需要底层的参加)
		*实现
			1.标准的接口:DataSource	(java.sql包内的)
				1.方法;
					*获取连接:getConnection()---->获取连接
					*归还连接:如果连接对象Connetion是从连接池中获取的,那么调用的不是关闭连接,而是归还连接到容器中,他们名字都相同,意义不同;调用Connection.close(); 
			2.一般我们不去实现它,有数据库厂商来实现
				1.C3P0:数据库连接池技术
				2.Druid:数据库连接池实现技术,有阿里巴巴提供。
			3.C3P0:数据库连接池技术
					*步骤
						 1.导入jar包(两个) C3P0-0.9.2.jar and  mchange-commons-java-0.2.12.jar还有导入mysql的驱动包			 
						 2.	定义配置文件:
								*名称:c3p0.properties 或者 c3p0-config.xml(名称是固定了的,其自带的有)
								*路径:ClassPath路径下(类路径下),直接将文件放在src目录下
						 3.创建核心对象,数据库连接池对象ComboPooledDataSource
						 4.获取连接:getConnection
			 4.Druid:数据库连接池,由阿里巴巴提供
					1.步骤:
						1.导入jar包 druid-1.0.9.jar
						2.定义配置文件
							*是properties形式的
							*可以叫任意名称,放置在任意位置
						3.加载配置文件,properties	
						4.获取数据库的连接池对象;通过工厂类来获取 DruidDataSourceFactory
						5.获取连接:getConnection();
					2.定义一个工具类
					    1.定义一个类 JDBCUtils
					    2.使用静态代码块来加载配置文件properties,初始化连接池对象。
					    3.提供的方法
						    1.获取连接方法:通过数据库连接池获取连接
						    2.提供一个获取连接池对象的方法
							3.释放资源			 
7.spring JDBC: JDBC Template模板
	##spring 框架对JDBC的简单封装,提供了JDBCTemplate对象简化JDBC的开发
	*步骤
		1.导入jar包
		2.创建JDBCTemplate对象,依赖于数据源DataSource对象
			*JDBCTemplate template = new JDBCTemplate(ds);
		3.调用JDBCTemplate对象的方法来完成操作
			*update()-->增删改语句,使用的是prepareStatement的sql 格式,这个例如,update(sql,第一个?的赋值 , 第二个?的赋值,.......)
			*queryForMap():查询结果集封装成map集合
			*queryForList():查询结果封装为List集合
			*query():查询结果,将结果封装为JavaBean对象
				*query的参数:RowMapper
					*一般我们在使用BeanPropertyRowMapper<类型>(类型的字节码对象)(实现了RowMapper接口),因此可以使用他们来实现接口回调来完成数据的自动封装
					*new BeanPropertyRowMapper<类型>(类型的字节码对象)
			*queryForObject:查询结果,将结果封装为Object对象	
		4.练习
			*需求
				1.查询所有记录将其封装为List集合
						*返回得到记录的集合,一个map获取一条记录,所以这个是记录的集合,将map作为排队元素 List<Map<String,Object>> list = template.queryForList(sql,......);
				2.查询id为1的记录所有记录将其封装为Map集合  返回记录只能是一条记录,否则会报错;因为字段名当成map的键,记录当成值。     
						*一条记录封装成一个map集合(期望一条记录)
				3.查询所有记录,将其封装为对象Emp对象的List集合
					*使用query()方法(期间会使用到接口参数,就需要使用内部类来重写接口中的方法),来使用Emp来记录信息,列成List集合类返回。
							(****重点****)其中,如果自己使用的是自定类的时候,使用基本数据类型是不能接受数据库表记录中的NULL的,因此在读取值中含有NULL的时候,就是使用引用数据类型的,不使用基本数据类型  比如 double-->Double ,int--->Integer ,boolean--->Boolean 可以接受为NULL的返回值
					*案例代码:		
					//使用内部匿名类进行对自己封装的类的初始化  
	  List<Emp>list = template.query(sql, new RowMapper<Emp>(){  
	  
	        @Override  
	  public Emp mapRow(ResultSet resultSet, int i) throws SQLException {  
	            Emp emp = new Emp();  
	  int empno = resultSet.getInt("empno");  
	  String ename = resultSet.getString("empno");  
	              
	  String job = resultSet.getString("job");  
	  int mgr = resultSet.getInt("mgr");  
	  Date hiredate = resultSet.getDate("hiredate");  
	  double sal = resultSet.getDouble("sal");  
	  double comm = resultSet.getDouble("comm");  
	  int deptno = resultSet.getInt("deptno");  
	  
	  emp.setEmonp(empno);  
	  emp.setEname(ename);  
	  emp.setJob(job);  
	  emp.setMgr(mgr);  
	  emp.setHiredate(hiredate);  
	  emp.setSal(sal);  
	  emp.setComm(comm);  
	  emp.setDeptno(deptno);  
	 return emp;  
	  }  
	    });  //内部匿名类的写法  
	  Iterator<Emp> iterator = list.iterator();  
	 while (iterator.hasNext()){  
	        System.out.println(iterator.next());  
	  }  
	}
				
			4.查询总记录数(就是利用select查询得到的是一个数,不是一个记录的使用使用的方法)
				*Long long = template.queryForObject(sql,Long.class(long的字节码对象))
			
				*补充知识:注解@Test,可以使用其注释部分单独运行,测试	

猜你喜欢

转载自blog.csdn.net/qq_45788043/article/details/111599889