Mybatis学习笔记一
Posted 冰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis学习笔记一相关的知识,希望对你有一定的参考价值。
Mybatis介绍
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
使用jdbc编程问题总结
- 数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。如果使用数据库连接池可解决此问题。
- Sql语句在代码中硬编码,造成代码不易维护,实际应用中sql变化的可能较大,sql变动需要改变java代码。
- 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
- 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。
Mybatis架构
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编程中对结果的解析处理过程。
Mybatis入门程序
1、pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.yyb</groupId> <artifactId>mybitis</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.7</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.8</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency> </dependencies> <build> <finalName>mybatis</finalName> <!--配置jdk版本为1.8--> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> </project>
2、创建数据库,准备数据。
/* Navicat MySQL Data Transfer Source Server : localhost_3306 Source Server Version : 50521 Source Host : localhost:3306 Source Database : mybatis Target Server Type : MYSQL Target Server Version : 50521 File Encoding : 65001 Date: 2015-04-09 16:03:53 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for `orders` -- ---------------------------- DROP TABLE IF EXISTS `orders`; CREATE TABLE `orders` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT \'下单用户id\', `number` varchar(32) NOT NULL COMMENT \'订单号\', `createtime` datetime NOT NULL COMMENT \'创建订单时间\', `note` varchar(100) DEFAULT NULL COMMENT \'备注\', PRIMARY KEY (`id`), KEY `FK_orders_1` (`user_id`), CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of orders -- ---------------------------- INSERT INTO `orders` VALUES (\'3\', \'1\', \'1000010\', \'2015-02-04 13:22:35\', null); INSERT INTO `orders` VALUES (\'4\', \'1\', \'1000011\', \'2015-02-03 13:22:41\', null); INSERT INTO `orders` VALUES (\'5\', \'10\', \'1000012\', \'2015-02-12 16:13:23\', null); -- ---------------------------- -- Table structure for `user` -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL COMMENT \'用户名称\', `birthday` date DEFAULT NULL COMMENT \'生日\', `sex` char(1) DEFAULT NULL COMMENT \'性别\', `address` varchar(256) DEFAULT NULL COMMENT \'地址\', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES (\'1\', \'王五\', null, \'2\', null); INSERT INTO `user` VALUES (\'10\', \'张三\', \'2014-07-10\', \'1\', \'北京市\'); INSERT INTO `user` VALUES (\'16\', \'张小明\', null, \'1\', \'河南郑州\'); INSERT INTO `user` VALUES (\'22\', \'陈小明\', null, \'1\', \'河南郑州\'); INSERT INTO `user` VALUES (\'24\', \'张三丰\', null, \'1\', \'河南郑州\'); INSERT INTO `user` VALUES (\'25\', \'陈小明\', null, \'1\', \'河南郑州\'); INSERT INTO `user` VALUES (\'26\', \'王五\', null, null, null);
3、创建pojo
package cn.itcast.mybatis.po; import java.io.Serializable; import java.util.Date; public class Orders implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private Integer id; private Integer userId; private String number; private Date createtime; private String note; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number == null ? null : number.trim(); } public Date getCreatetime() { return createtime; } public void setCreatetime(Date createtime) { this.createtime = createtime; } public String getNote() { return note; } public void setNote(String note) { this.note = note == null ? null : note.trim(); } }
package cn.itcast.mybatis.po; import java.io.Serializable; import java.util.Date; public class User implements Serializable { /** * */ private static final long serialVersionUID = 1L; private Integer id; private String username;// 用户姓名 private String sex;// 性别 private Date birthday;// 生日 private String address;// 地址 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address=" + address + "]"; } }
4、在resources下加入log4j.properties和SqlMapConfig.xml配置文件
mybatis默认使用log4j作为输出日志信息。log4j.properties配置如下:
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
SqlMapConfig.xml是mybatis核心配置文件,配置文件内容为数据源、事务管理。配置如下:
<?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> <!-- 和spring整合后 environments配置将废除 --> <environments default="development"> <environment id="development"> <!-- 使用jdbc事务管理 --> <transactionManager type="JDBC" /> <!-- 数据库连接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> </configuration>
5、在resources下创建一个mapper文件夹,添加User.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"> <!-- namespace:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 --> <mapper namespace="test"> <!-- id:statement的id 或者叫做sql的id--> <!-- parameterType:声明输入参数的类型 --> <!-- resultType:声明输出结果的类型,应该填写pojo的全路径 --> <!-- #{}:输入参数的占位符,相当于jdbc的? --> <select id="queryUserById" parameterType="int" resultType="com.yyb.pojo.User"> SELECT * FROM user WHERE id = #{id} </select> </mapper>
6、添加测试类
package com.yyb.test; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; /** * Created by Administrator on 2017/8/15. */ public class Test { @org.junit.Test public void func1() { String path = "SqlMapConfig.xml"; InputStream resourceAsStream = null; try { // 1. 加载SqlMapConfig.xml配置文件 resourceAsStream = Resources.getResourceAsStream(path); } catch (IOException e) { e.printStackTrace(); } // 2. 创建SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); //3. 创建SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 4. 执行SqlSession对象执行查询,获取结果User // 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数; Object user = sqlSession.selectOne("test.queryUserById", 1); // 5. 打印结果 System.out.println(user); // 6. 释放资源 sqlSession.close(); } }
最终项目结构如下:
7、测试效果:User [id=1, username=王五, sex=2, birthday=null, address=null]
实现根据用户名模糊查询用户
在user.xml中添加以下代码:
<!-- //根据用户名称模糊查询用户列表 #{} select * from user where id = ? 占位符 ? == \'五\' ${} select * from user where username like \'%五%\' 字符串拼接 区别主要是单引号的问题 #{}会加单引号 ${value}不会加单引号,名字必须为value --> <select id="findByUserName" parameterType="String" resultType="com.yyb.pojo.User"> SELECT * FROM user WHERE username like \'%${value}%\'
--也可以这样,防止SQL注入:SELECT * FROM user WHERE username like "%"#{value}"%"
</select>
测试代码如下:
@org.junit.Test public void func2() { String path = "SqlMapConfig.xml"; InputStream resourceAsStream = null; try { // 1. 加载SqlMapConfig.xml配置文件 resourceAsStream = Resources.getResourceAsStream(path); } catch (IOException e) { e.printStackTrace(); } // 2. 创建SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); //3. 创建SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 4. 执行SqlSession对象执行查询,获取结果User // 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数; List<User> users = sqlSession.selectList("test.findByUserName", "五"); // 5. 打印结果 System.out.println(users); // 6. 释放资源 sqlSession.close(); }
#{}和${}的区别
#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
parameterType和resultType
parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。
resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List中
selectOne和selectList
selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3 at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)
selectList可以查询一条或多条记录。
实现添加用户
在user.xml中添加如下代码:
<insert id="addUser" parameterType="com.yyb.pojo.User" > INSERT into USER(username,birthday,address,sex) VALUES (#{username},#{birthday},#{address},#{sex}) </insert>
测试代码如下;
@org.junit.Test public void func3() { String path = "SqlMapConfig.xml"; InputStream resourceAsStream = null; try { // 1. 加载SqlMapConfig.xml配置文件 resourceAsStream = Resources.getResourceAsStream(path); } catch (IOException e) { e.printStackTrace(); } // 2. 创建SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); //3. 创建SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 4. 执行SqlSession对象执行查询,获取结果User // 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数; User user=new User(); user.setUsername("yyb"); user.setSex("男"); user.setBirthday(new Date()); user.setAddress("cd");以上是关于Mybatis学习笔记一的主要内容,如果未能解决你的问题,请参考以下文章