谈jdbcTemplate与mybatis
为什么会产生 Hibernate Mybatis 这类的dao层框架
传统的jdbc 虽然执行速度很快,但是开发效率很低,随着面向对象开发的设计思想,在面向对象编程中 将对象 进行持久化,存入关系型的数据库时,由于关系型数据库的设计思想是数学思维,在持久化时,必须要对象拆分各个属性值,才可存入数据库;传统的jdbc 持久化时 对象持久化时 ,取出对象的一个一个属性,过去繁琐,并且不便于维护,而市场上的面向对象的数据库还并不成熟,所以为了调节面向对象设计的开发思想与落后的关系型数据库之间持久化时繁琐的问题,产生了一种新的设计规范
ORM (Object Relation Mapping)
Spring对数据库的操作在jdbc上面做了深层次的封装,也就是工具类 jdbcTemplate
先看一下jdbcTemplate的大致流程图
作用:
1: 它提供了AOP式的事务管理
AOP式的事物管理:在以前的事务管理是要融合在逻辑代码中的,在逻辑代码中决定事务是否提交或者回滚,这样很容易造成代码难以维护,代码冗余
但是使用spring的声明式事务后,只需要在数据库处理方法上注解事务,就可以对操作进行管理,事务的设置和逻辑代码分开,容易维护。
<!-- 定义template组件 --> <bean id="template" class="org.springframework.jdbc.core.JdbcTemplate"> <!-- 注入连接信息 --> <property name="dataSource" ref="bonecp"> </property> </bean>
com.alibaba.druid.pool.DruidDataSource
<!-- DataSource 数据源 连接池 存储管理大量的链接 流行的 dbcp c3p0,proxool --> <!-- 数据源配置, 使用 BoneCP 数据库连接池 --> <bean id="bonecp" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass --> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <!-- 基本属性 url、user、password --> <property name="url" value="jdbc:mysql://localhost:3306/medicine?useUnicode=true&characterEncoding=utf-8" /> <property name="username" value="root" /> <property name="password" value="root" /> <!-- 配置获取连接等待超时的时间 --> <property name="maxWait" value="60000" /> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="300000" /> <property name="testWhileIdle" value="true" /> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> <!-- 配置监控统计拦截的filters --> <property name="filters" value="stat" /> </bean>
下一部是根据表 编写实体类
实体类
package com.mxp.jdbc.entity; import java.io.Serializable; public class User implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String id; private String userName; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
还需要根据实体类写一个rowmapper
注意这里要继承
org.springframework.jdbc.core.RowMapper,然后重写maprow方法
package com.mxp.jdbc.entity; import java.sql.ResultSet; import java.sql.SQLException; import org.springframework.jdbc.core.RowMapper; /** * 每个实体类都有这个封装组件 * 将User记录封装成 User对象 * @author Administrator * */ public class UserRowMapper implements RowMapper<User>{ /** * arg1:第几行记录 */ @Override public User mapRow(ResultSet arg0, int arg1) throws SQLException { User user = new User(); user.setId(arg0.getString("id")); user.setUserName(arg0.getString("user_name")); return user; } }
下面可以编写dao了 编写之前我们在spring的主配置文件中要把spring的扫描组件启动
<!-- spring组件扫描 --> <context:component-scan base-package="com.mxp"> </context:component-scan>
dao
package com.mxp.jdbc.dao; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import com.mxp.jdbc.entity.User; import com.mxp.jdbc.entity.UserRowMapper; @Repository public class ItinerantDAO { @Autowired private JdbcTemplate template;//注入的方式 public void save(User user){ String sql = "insert into test_user" + "(id,user_name) values (?,?)"; Object[] params = { user.getId(),user.getUserName() }; template.update(sql, params); } public List<User> findAll(){ String sql ="select * from test_user"; UserRowMapper rowMapper = new UserRowMapper(); List<User> list = template.query(sql, rowMapper); return list; } }
那现在就可以写测试方法
package test; import java.io.IOException; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.mxp.ControllerQW; import com.mxp.jdbc.dao.ItinerantDAO; import com.mxp.jdbc.entity.User; import com.mxp.mybatis.util.MybatisUtil; public class Test { public static void main(String[] args) {
//spring的主配置文件名 String conf = "spring-context.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(conf); ItinerantDAO dao = ac.getBean("itinerantDAO",ItinerantDAO.class); User user = new User(); user.setId("1455"); user.setUserName("文森特"); dao.save(user); } @org.junit.Test public void test(){
String conf = "spring-context.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(conf); ItinerantDAO dao = ac.getBean("itinerantDAO",ItinerantDAO.class); List<User> list = dao.findAll(); for(User u:list){ System.out.println(u.getUserName()); } } }
这jdbcTemplate 见的次数很少 至今为止 还没有见到用的
Mybatis
原来在我们使用jdbc的问题
1 对数据库的连接 使用时就创建连接,不使用就立即释放,对数据库进行频繁连接开启和关闭,造成数据库的资源浪费,影响数据库的性能;
解决办法:使用数据库连接池,管理数据库的连接。
2 将sql语句硬编码到java代码中,如果sql语句修改,需要重新编译java代码,不利于系统维护,
解决办法:把sql语句I定义到xml配置文件里;
3 在向statement中设置参数,对站位符位置和设置参数数值,硬编码到java代码中,
4 从result结果集中遍历数据时,存在硬编码,讲获取表的字段名硬编码,不便于维护,
讲结果集 自动映射成java对象
mybatis的架构
是一个持久层的项目,是阿帕奇的顶级项目,
通过 mybatis提供的映射方式,半自动的生成sql,大部分还是需要程序员编写sql
核心:输入映射:可以将statement中的输入参数自动输入到映射 通过ongl表达式,将查询的结果集灵活映射成为java对象(输出映射)
1、 mybatis配置
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、 mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
5、 Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6、 Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过 Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
7、 Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过 Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="environment"> <environment id="environment"> <transactionManager type="JDBC" /> <!-- mybatis 自带连接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/medicine?useUnicode=true&characterEncoding=utf-8" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> <!-- 定义sqlMapper文件位置的 --> <mappers> <mapper resource="com/mxp/mybatis/entity/UserMapper.xml" /> </mappers> </configuration>
第二步 实体类及其sqlmap映射文件
package com.mxp.mybatis.entity; import java.io.Serializable; public class User implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String id; private String userName; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mxp.mybatis.entity.UserMapper"> <sql id="userColumns"> a.id AS "id", a.user_name AS "userName" </sql> <select id="findAll" resultType="com.mxp.mybatis.entity.User" > SELECT <include refid="userColumns"/> FROM test_user a </select> <select id="findLikeName" parameterType="string" resultType="com.mxp.mybatis.entity.User" > SELECT <include refid="userColumns"/> FROM test_user a <where> a.user_name like #{name} </where> </select> </mapper>
第三部 获取sqlsession
package com.mxp.mybatis.util; import java.io.InputStream; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class MybatisUtil { public static SqlSession getInsertance(){ SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //这是读取文件后 形成一个输入流 涨知识了 //Test 其实就是一个类型 写自己的什么类型都行 主要是为了获取到getClassLoader().getResourceAsStream InputStream reader = MybatisUtil.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml"); //获取sqlsessionFactory SqlSessionFactory factory = builder.build(reader); //获取session SqlSession session = factory.openSession(); return session; } }
第四部 写测试类
package test; import java.io.IOException; import java.util.List; import org.apache.ibatis.session.SqlSession; import com.mxp.mybatis.util.MybatisUtil; public class Test { @org.junit.Test public void getSqllSession() throws IOException{ SqlSession session = MybatisUtil.getInsertance(); System.out.println("获取session"); session.close(); } @org.junit.Test public void findall(){ SqlSession sqlsession = MybatisUtil.getInsertance(); List<com.mxp.mybatis.entity.User> list = sqlsession.selectList("findAll"); for(com.mxp.mybatis.entity.User u:list){ System.out.println(u.getUserName()); } sqlsession.close(); } @org.junit.Test public void findLike(){ SqlSession sqlsession = MybatisUtil.getInsertance(); List<com.mxp.mybatis.entity.User> list = sqlsession.selectList("findLikeName","%文%"); for(com.mxp.mybatis.entity.User u:list){ System.out.println(u.getUserName()); } sqlsession.close(); } }
Mybatis的
Mapper映射器接口规则,会自动生成接口实现类。
修饰public
a.根据sqlMapper定义的id属性当接口方法名
b 根据sqlMapper定义的parameterType类型定义参数类型
c 根据sqlMapper定义的resultType的类型 定义方法的返回类型
(多行使用list<泛型(resultType的类型)>,单行使resultType的类型)
d 将sqlMapper的namespace属性指定成为 包名.接口名字,就是接口的位置,
如何取到接口实现类呢
从sqlsession中获取
sqlsession.getMapper(接口的class对象);
mybatis替我生成实现类,在实现类中把sqlsession.select*的各种操作封装起来
首先实现 d
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mxp.mybatis.dao.UserDao"> <sql id="userColumns"> a.id AS "id", a.user_name AS "userName" </sql> <select id="findAll" resultType="com.mxp.mybatis.entity.User" > SELECT <include refid="userColumns"/> FROM test_user a </select> <select id="findLikeName" parameterType="string" resultType="com.mxp.mybatis.entity.User" > SELECT <include refid="userColumns"/> FROM test_user a <where> a.user_name like #{name} </where> </select> </mapper>
a b c
package com.mxp.mybatis.dao; import java.util.List; import com.mxp.mybatis.entity.User; public interface UserDao { public List<User> findAll(); public List<User> findLikeName(String name); }
测试生成的映射器接口实现类
@org.junit.Test public void testMapper(){ SqlSession sqlsession = MybatisUtil.getInsertance(); UserDao dao = sqlsession.getMapper(UserDao.class); List<com.mxp.mybatis.entity.User> os = dao.findAll(); for(com.mxp.mybatis.entity.User u:os){ System.out.println(u.getUserName()); } sqlsession.close(); }