mybatis——持久层各种实现
一、JDBC
一个简单的JDBC连接
public class JDBCTest { public static void main(String[] args) throws Exception { //Class.forName("com.mysql.jdbc.Driver");1.5后SPI机制 //打开连接 Connection con = DriverManager.getConnection("jdbc:mysql://mcip:3306/study","root","123456"); //创建语句 Statement statement = con.createStatement(); //指定sql并执行 ResultSet resultSet = statement.executeQuery("select * from user"); //循环遍历结果集 while (resultSet.next()){ //处理每条数据 System.out.println(resultSet.getString("user_id")+"-"+ resultSet.getString("user_name")); } //关闭连接 con.close(); } }
简单的JDBC存在诸多的缺点:
① 打开关闭连接
② 每次执行sql时,都要创建statement,然后执行
③ 结果集处理:循环遍历+处理每条数据
④ 没有事务的支持
二、JDBCTemplate
JDBCTemplate是spring-jdbc.jar中的核心类,借用下官网中的表格(第3节)
可以看出:spring-jdbc只是一个部分解决方案,还算不上一个整体解决框架,主要解决了
① 自动打开释放连接
② 自动创建statement,开发仅需要指定sql语句,及参数
③ 事务的支持
④ 优化了结果集的遍历,但每条数据还是要开发人员处理
简单JDBCTemplate实现:
public class JdbcTemplateTests { private static JdbcTemplate jdbcTemplate = null; static { //创建数据源 try (InputStream in = new FileInputStream("D:\\myGItHub\\spring-framework\\spring-study\\src\\test\\resources\\db.properties");){ Properties properties = new Properties(); properties.load(in); SimpleDriverDataSource dataSource = new SimpleDriverDataSource(); Class DriverClass = Class.forName(properties.getProperty("mysql.driver")); dataSource.setDriverClass((Class<? extends Driver>) DriverClass); dataSource.setUrl(properties.getProperty("mysql.url")); dataSource.setUsername(properties.getProperty("mysql.username")); dataSource.setPassword(properties.getProperty("mysql.password")); //创建jdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } @Test public void jdbcTemplateTest(){ List<User> list = jdbcTemplate.query("select * from user", new RowMapper<User>() { @Override public User mapRow(ResultSet rs, int rowNum) throws SQLException { User user = new User(); user.setId(rs.getLong("id")); user.setUserId(rs.getLong("user_id")); user.setUserName(rs.getString("user_name")); return user; } }); if (list.isEmpty()){ return; } User user = list.get(0); System.out.println(user); jdbcTemplate.update("update user set user_name = ? where id = ?","9527",user.getId()); Map<String,Object> map = jdbcTemplate.queryForMap("select * from user where id = ?",user.getId()); System.out.println(map); } }
jdbcTemplate还遗留的问题:
① 结果集的每条数据,需要开发人员自己处理
② sql语句Java代码强耦合
三、mybatis与Hibernate
为解决上面所有问题而产生的整体性框架,例如mybatis、Hibernate。
① 结果集的每条数据自动映射成一个java对象
② sql在xml中配置与Java代码解耦(mybatis),直接去sql开发(hibernate)
1、常见的两个术语ORM与JPA
ORM:是Object Relational Mapping简称,中文名为对象关系映射。是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。本质就是实现程序对象到关系数据库数据的映射,程序对象操作会直接自动生成sql,然后操作数据库数据。不需要开发人员写sql语句。
JPA:是Java Persistence API简称,中文名为Java持久层API。由sun公司提供的POJO持久化标准规范,主要为了实现ORM。
JPA包括以下3方面技术:
ORM映射元数据:JPA支持xml或者注解两种元数据形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库中;
API:用来操作实体对象,执行CRUD操作,框架在后台代替我们完成所有的事情(包括自动生成sql),将开发人员从繁琐的JDBC和SQL代码中解脱出来
查询语言:通过面向对象而非面向数据库查询语言查询数据,避免程序的SQL语句紧密耦合。
2、mybatis与hibernate对比
hibernate:是一个全自动的ORM框架,开发人员仅需要操作映射对象,能自动生成sql语句,然后自动执行。有自己的HQL可提供更加灵活的查询能力。
mybatis:不是一个全自动的ORM框架,程序与数据库打交道还是通过开发人员写SQL语句来完成的,但保留了对象和表数据的映射关系,所以也称为半自动ORM框架(将SQL语句交由开发人员编写)。
3、mybatis简单实现
mybatis原名是ibatis,3.0版本后改名为mybatis,框架改名意味着有重大升级
3.0之前即ibatis仅允许XML映射器,所有sql都在xml文件中配置,且这个xml文件需要配置到configuration下<mapper>中。使用时需要先引入SqlSession,然后执行
private SqlSession session; public void setSqlSessino(SqlSession session){ this.session = session; } User s = session.selectOne("com.app.aop.transactional.mapper.UserMapper.selectByPrimaryKey", 1L);
3.0之后即mybatis开始支持接口映射器,其底层采用接口绑定技术。sql可以在接口方法上注解,也可以在xml文件中配置,提供一个接口解析器扫描某个package下所有的接口,不需要再配置<mapper>了
@Autowired private UserMapper userMapper;//ali插件不建议这么注入了,建议采用构造方法注入 User s = userMapper.selectByPrimaryKey(1L);
简单实现:
public class MybatisTests { public static void main(String[] args) throws Exception { // 读取mybatis-config.xml文件 InputStream inputStream = Resources.getResourceAsStream("mybatis-conf.xml"); // 初始化mybatis,创建SqlSessionFactory类的实例 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 创建Session实例 SqlSession session = sqlSessionFactory.openSession(); // 操作数据库方法一(ibatis主要使用方式):获得xml映射文件中定义的操作语句 User s = session.selectOne("com.app.aop.transactional.mapper.UserMapper.selectByPrimaryKey", 1L); // 打印Student对象 System.out.println(s); // 操作数据库方法二(mybatis主要使用方式):获得mapper接口的代理对象 UserMapper sm = session.getMapper(UserMapper.class); // 直接调用接口的方法,查询id为1的Student数据 User s2 = sm.selectByPrimaryKey(1L); // 打印Peson对象 System.out.println(s2); // 提交事务 session.commit(); // 关闭Session session.close(); } }
mybatis-conf.xml
<?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> <!-- 属性:定义配置外在化 --> <properties resource="db.properties" /> <!-- 环境:配置mybatis的环境 --> <environments default="dev"> <!-- 环境变量:可以配置多个环境变量,比如使用多数据源时,就需要配置多个环境变量 --> <environment id="dev"> <!-- 事务管理器 --> <transactionManager type="JDBC"></transactionManager> <!-- 数据源 --> <dataSource type="POOLED"> <property name="driver" value="${mysql.driver}"/> <property name="url" value="${mysql.url}"/> <property name="username" value="${mysql.username}"/> <property name="password" value="${mysql.password}"/> </dataSource> </environment> </environments> <!-- 映射器:指定映射文件或者映射类 --> <mappers> <mapper resource="mapper/UserMapper.xml"/> </mappers> </configuration>
db.propertis
mysql.driver=com.mysql.cj.jdbc.Driver
mysql.url=jdbc:mysql://mcip:3306/study
mysql.username=root
mysql.password=123456
UserMapper.xml
<?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.app.aop.transactional.mapper.UserMapper"> <resultMap id="BaseResultMap" type="com.app.aop.transactional.model.User"> <id column="id" jdbcType="BIGINT" property="id" /> <result column="user_id" jdbcType="BIGINT" property="userId" /> <result column="user_name" jdbcType="VARCHAR" property="userName" /> </resultMap> <sql id="Base_Column_List"> id, user_id, user_name </sql> <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from user where id = #{id,jdbcType=BIGINT} </select> </mapper>
UserMapper.java
public interface UserMapper { User selectByPrimaryKey(Long id); }