44、Spring整合JDBC

学习目标:

1、Spring整合JDBC

2、掌握JdbcTemplate的使用

学习过程:

昨天我们讲过spring的一个特点是“不要重复发明轮子”。由于java世界里,对一些问题已经有很多非常好用的第三方技术了,spring一般不会重新开发一个,但是spring作为一个容器需要整合这些技术,所有知识简单的整合了这些技术,把他们封装到spring的容器里面,使得这些技术更加好用,所有spring能够这么快就流行起来了。这天我们就讲讲spring是如何整合JDBC和struts2这两个框架的。

一、新建项目

为了讲解今天这节课我们就先建立一个spring的数据库,然后建立一张表,一会我们将会使用spring提供的jdbc的实现操作这个表。表实现代码如下:

DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
  `dep_id` int(11) NOT NULL AUTO_INCREMENT,
  `dep_name` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`dep_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后,我们还需要导入相关的包,

二、spring连接数据库

我们先讲讲如何整合jdbc吧,通过这节课的学习,你就会知道spring是如何简化了对数据库的操作。要操作数据库,我们首先第一步是需要连接数据库,为了连接数据库,spring定义了几个不同的连接数据源,其中最简单的就是DriverManagerDataSource,每一次请求都会生成一个连接,所以效率不高,实现代码如下:

<!-- 建立一个连接组件 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" ></property>
    <property name="url" value="jdbc:mysql://localhost:3306/spring"></property>
    <property name="username" value="root"></property>
    <property name="password" value="123456"></property>
</bean>

大家看到,非常简单,指定基本的连接信息就可以了。当然我们也可以使用SingleConnectionDataSource,它是SmartDataSource接口的一个实现,其内部包装了一个单连接。该连接在使用之后将不会关闭,很显然它不能在多线程的环境下使用。 

上面两个数据源都非常适合在测试时候使用,但是如果我们需要在生产环境下使用就不适合了,因为效率都不高,我们以前学习过可以使用连接池的方式以提高效率,spring对dbcp和c3p0等连接池技术都有支持,我们也可以使用连接池的数据源,记住,spring并没有开发一个新的数据连接池,所有如果你需要使用上面的连接池技术,那么你要把相关的包先导入尽量,比使用dbcp连接池,那么你需要先把dbcp连接池所需要的包先导入尽量,然后把上面的连接组件的class实现改成dbcp就可以了,代码如下:

<!-- 建立一个连接组件 -->
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" ></property>
        <property name="url" value="jdbc:mysql://localhost:3306/spring"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
        <!-- 你现在就可以配置连接池的信息了。-->
         <property name="initialSize" value="5"></property> 
          <property name="maxActive" value="15"></property> 
</bean>

三、使用JdbcTemplate模板类,简化数据库的操作

以前操作数据库我们都知道封装一个BaseDao类,现在你当然还可以这样做,只是spring已经帮我们封装了一个更加强大,所有这部分工作我们就可以省了。在容器中声明JdbcTemplate组件,该组件需要依赖数据源组件,所以需要注入上面定义的数据源组件,代码如下:

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
   <property name="dataSource" ref="dataSource"></property>
</bean>

然后我们就可以实现自己的业务逻辑了。一般我们建议你还是使用面向接口的方式编程,虽然这不是必须的,但是我们还是为部门操作类定义一个接口。

/**
 * 对Department表操作
 * @author Administrator
 *
 */
public interface DepartmentDao {
    public void add(Department department);
    public int delete(int id);
    public void update(Department department);
    public Department query(int id) ;
    public List<Department> queryByCondition();
    public List<Department> queryByCondition(String name);
}

这节课我们先实现增收改操作,下一节我们在实现查询功能。定义一个实现了,这个实现了需要使用JdbcTemplate模板组件,这里我们使用属性注入的方式,先定义一个JdbcTemplate jdbcTemplate对象,然后在生产一个set的方法,这样才能使用属性注入,DepartmentDaoImpl实现了的代码如下:

public class DepartmentDaoImpl implements DepartmentDao {

	private JdbcTemplate jdbcTemplate;

	public void add(Department department) {
		final String sql = "insert into department(dep_name)  values(?)";
		jdbcTemplate.update("insert into department(dep_name)  values(?)",
				new Object[] { department.getDepName() });
	}

	public int delete(int id) {
		return jdbcTemplate.update("delete from department where dep_id=?",
				new Object[] { id });
	}

	public void update(Department department) {
		jdbcTemplate
				.update("update department set dep_name=? where dep_id=?",
						new Object[] { department.getDepName(),
								department.getDepId() });
	}

	public Department query(int id) {
		Department department = null;
		return department;
	}

	public List<Department> queryByCondition() {
		return null;
	}

	public List<Department> queryByCondition(String name) {
		return null;
	}

	// spring属性注入
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}
}

 记住所有的组件都要交给spring容器管理,所有你先不要写个main方法,然后通过我们以前new一个dao对象调用方法,现在我们需要在spring的容器中定义这个组件。

<!--spring 整合jdbc  部门dao -->
	<bean id="departmentDao" class="com.dao.impl.DepartmentDaoImpl" >
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>	
	</bean>

并注入jdbctemplate组件。然后我们在写一个main方法测试是否能正常操作数据库。

public static void main(String[] args) {
	ApplicationContext context = new FileSystemXmlApplicationContext(
				"src/springContext.xml");
	DepartmentDao departmentDao = (DepartmentDao) context
				.getBean("departmentDao");
	Department department = new Department();
	department.setDepName("test");
	departmentDao.add(department);

}

运行上面的代码,如果没有问题就应该插入成功了。可见这个jdbcTemplate和我们之前封装的BaseDao的使用差不多,事实这个jdbcTemplate还有很多高级的使用方法。下面我们就简单讲解一下。

一、获得用户刚刚插入数据的id

这个问题我们以前做项目的时候碰到过,不同的数据的自增方式是不同的,所有要去的刚刚插入的数据库的那条数据的id不同的数据库也有不同实现方法,但是jdbcTemplate已经帮我们封装好了。所有我们可以很方便的获得这个值,修改add方法,当插入完成后可以获得刚刚插入这条数据在数据库中对应的id。只需要使用KeyHolder对象就可以了,实现代码如下:

  public void add(final Department department) {
        final String sql="insert into department(dep_name)  values(?)";

/*      jdbcTemplate.update("insert into department(dep_name)  values(?)",
                new Object[] { department.getDepName() });*/
        KeyHolder keyHolder=new GeneratedKeyHolder();
        jdbcTemplate.update(new PreparedStatementCreator() {
            public PreparedStatement createPreparedStatement(Connection arg0)
                    throws SQLException {
                PreparedStatement ps=jdbcTemplate.getDataSource().getConnection().prepareStatement(sql);
                ps.setString(1, department.getDepName());
                return ps;
            }
        },keyHolder);
        //重新set进去
        department.setDepId(keyHolder.getKey().intValue());
    }

再次测试上面的代码

  public static void main(String[] args) {
        ApplicationContext context = new FileSystemXmlApplicationContext(
                "src/springContext.xml");
        DepartmentDao departmentDao = (DepartmentDao) context
                .getBean("departmentDao");

         Department department = new Department();
         department.setDepName("test2"); 
         departmentDao.add(department);
         System.out.println("数据库对应生成的id:"+department.getDepId());
    }

二、查询操作

下面我们研究一下查询操作,原始的jdbc查询是返回的是ResultSet对象,然后把数据库的字段值逐个set到javaBean对象的属性中。jdbcTemplate也是差不多,只是它返回的是一个Map对象,map的key对应的就是字段名称,下面我们实现根据id进行查询的操作,代码如下:

   public Department query(int id) {

        Department department = null;
        // 如果不使用RowMapper,那么就像以前ResultSet一样要一个个的set进去了。
        List<Map> maps = jdbcTemplate.queryForList(
                "select * from department where dep_id=?", new Object[] { id });
        if (maps != null && maps.size() > 0) {
            Map<Object, Object> map = maps.get(0);
            department = new Department();
            department.setDepId((Integer) map.get("dep_id"));
            department.setDepName(map.get("dep_name").toString());
        }
        return department;
    }

记得以前我们封装的高级jdbc把,那时候我们通过反射的方式写了一个自动ResultSet到javaBean对象的转换,其实jdbcTemplate也有类似的实现,只需要你实现RowMapper接口就可以了,我们使用内部类的方式,代码如下:

class DepartmentMap implements RowMapper{
        public Object mapRow(ResultSet rs, int arg1) throws SQLException {
            Department department=new Department();
            department.setDepId(rs.getInt("dep_id"));
            department.setDepName(rs.getString("dep_name"));
            return department;
        }
    }

实现查询全部和根据名称查询两个方法,只需要传入DepartmentMap对象就可以了。代码如下:

   public List<Department> queryByCondition() {
    List<Department> departments = jdbcTemplate.query("select * from department", new DepartmentMap());
    return departments;
}


public List<Department> queryByCondition(String name) {
  List<Department> departments = jdbcTemplate.query("select * from department where dep_name like '%"+name+"%'", new DepartmentMap());
    return departments;   
}

你可以在main方法中测试一下:

List<Department> departments=departmentDao.queryByCondition("t");
for(Department department2:departments){
    System.out.println(department2.getDepName());
}

猜你喜欢

转载自blog.csdn.net/liubao616311/article/details/85223140