mybatis
ibatis 亲爹 apache 后爹 google 后后爹github
开源的持久层框架
jdbc 代码繁琐 手写sql 速度快,性能好 就是麻烦
编程步骤
1、导包
2、添加mybatis配置文件
3、写实体类
4、写映射文件,修改配置文件,指定英文文件的位置
5、调用mybatis 提供的API SqlSession 提供的方法来访问数据库
1、导包
mybatis
mysql
2、配置文件
<?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> <!-- 环境:配置mybatis的环境 --> <environments default="environment"> <!-- 环境变量:可以配置多个环境变量,比如使用多数据源时,就需要配置多个环境变量 --> <environment id="environment"> <!-- 事务管理器 --> <transactionManager type="JDBC"></transactionManager> <!-- 数据源 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://172.29.12.158:3306/test?useUnicode=true&characterEncoding=utf8"/> <property name="username" value="zongxuan"/> <property name="password" value="zongxuan"/> </dataSource> </environment> </environments> <!-- 映射器:指定映射文件或者映射类 --> <mappers> <mapper resource="entity/MepMapper.xml"/> </mappers> </configuration>
3、实体类的属性名与表的字段表要求一样 大小写无所谓
package entity; public class Emp { private Integer id; private String name; private Double age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getAge() { return age; } public void setAge(Double age) { this.age = age; } @Override public String toString() { return "Emp [id=" + id + ", name=" + name + ", age=" + age + "]"; } }
4、写实体类
<?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="test"> <!-- id 唯一 parameterType 参数类型 #{} 实体类的属性 --> <insert id="save" parameterType="entity.Emp"> INSERT INTO emp2(name,age) VALUES(#{name},#{age}) </insert> <!-- resultType:返回结果的类型 最终的 --> <select id="findAll" resultType="entity.Emp"> SELECT * FROM emp2 </select> <select id="findById" parameterType="int" resultType="entity.Emp"> SELECT * FROM emp2 WHERE id=#{id} </select> <update id="modify" parameterType="entity.Emp"> UPDATE emp2 SET name=#{name},age=#{age} WHERE id=#{id} </update> <delete id="delete" parameterType="int"> DELETE FROM emp2 WHERE id=#{id} </delete> </mapper>
5、调用mybatis
package testCase; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Before; import org.junit.Test; import entity.Emp; public class TestMybats { private SqlSession ss; @Before public void init() { SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder(); SqlSessionFactory ssf = ssfb.build(TestMybats.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml")); ss = ssf.openSession(); } @Test public void t1() { Emp emp = new Emp(); emp.setName("李四"); emp.setAge(new Double("22")); ss.insert("test.save", emp); ss.commit(); ss.close(); } @Test public void t2() { List<Emp> emps = ss.selectList("test.findAll"); System.out.println(emps); ss.close(); } @Test public void t3() { Emp emp = ss.selectOne("test.findById", 4); System.out.println(emp); ss.close(); } @Test public void t4() { Emp emp = ss.selectOne("test.findById", 4); emp.setName("王五"); ss.update("test.modify", emp); ss.commit(); ss.close(); } @Test public void t5() { ss.delete("test.delete", 1); ss.commit(); ss.close(); } }
返回Map类型的结果
mybatis 会将查询结果先封装到一个map对象里面 字段名作为key 字段值作为value
然后再将map对象中的数据添加到实体对象里面
<select id="findById2" parameterType="int" resultType="map"> SELECT * FROM dept WHERE id=#{id} </select>
@Test public void t6() { Map data = ss.selectOne("dept.findById2",3); System.out.println(data); System.out.println(data.get("dname")); ss.close(); }
属性名和字段名不一样
1、在mybatis 映射文件SQL 中使用别名
2、使用ResultMap
1
2、
CREATE TABLE `emp2` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(30) DEFAULT NULL, `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8
package entity; public class Emp2 { private Integer emapNo; private String ename; private Double age; public Integer getEmapNo() { return emapNo; } public void setEmapNo(Integer emapNo) { this.emapNo = emapNo; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public Double getAge() { return age; } public void setAge(Double age) { this.age = age; } @Override public String toString() { return "Emp2 [emapNo=" + emapNo + ", ename=" + ename + ", age=" + age + "]"; }
}
<!-- 使用ResultMap 解决表的字段名和实体类的属性名不一致的情况 --> <!-- 处理表的字段名和实体类的属性名的对应关系 --> <resultMap type="entity.Emp2" id="emp2Map"> <result property="ename" column="name" /> <result property="emapNo" column="id" /> </resultMap> <select id="findById2" parameterType="int" resultMap="emp2Map"> SELECT * FROM emp2 WHERE id=#{id} </select>
@Test public void t6() { Emp2 emp = ss.selectOne("test.findById2",3); System.out.println(emp); ss.close(); }
Mapper 映射器
符合映射文件的接口
mybatis 会自动实现一个符合该接口要求的对象
要求:
a、接口方法的名称与映射中的sql的id要一样
b、方法的参数类型要与映射文件中的parameterType一致
c、方法的返回类型要与映射文件当中的resultType一致
映射文件的命名空间namespace要等于Mapper映射器的全限定名
<?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> <!-- 环境:配置mybatis的环境 --> <environments default="environment"> <!-- 环境变量:可以配置多个环境变量,比如使用多数据源时,就需要配置多个环境变量 --> <environment id="environment"> <!-- 事务管理器 --> <transactionManager type="JDBC"></transactionManager> <!-- 数据源 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://172.29.12.158:3306/test?useUnicode=true&characterEncoding=utf8"/> <property name="username" value="zongxuan"/> <property name="password" value="zongxuan"/> </dataSource> </environment> </environments> <!-- 映射器:指定映射文件或者映射类 --> <mappers> <mapper resource="entity/EmpMapper.xml"/> </mappers> </configuration>
package com.stevezong.mybatis.entity.dao; import java.util.List; import java.util.Map; import entity.Emp; import entity.Emp2; /** * Mapper映射器 就是一个接口 * * @author steve * */ public interface EmpDAO { void save(Emp emp); List<Emp> findAll(); Emp findById(int id); void delete(int id); void modify(Emp emp); Emp2 findById2(int id); }
<?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.stevezong.mybatis.entity.dao.EmpDAO"> <!-- id 唯一 parameterType 参数类型 #{} 实体类的属性 --> <insert id="save" parameterType="entity.Emp"> INSERT INTO emp2(name,age) VALUES(#{name},#{age}) </insert> <!-- resultType:返回结果的类型 最终的 --> <select id="findAll" resultType="entity.Emp"> SELECT * FROM emp2 </select> <select id="findById" parameterType="int" resultType="entity.Emp"> SELECT * FROM emp2 WHERE id=#{id} </select> <update id="modify" parameterType="entity.Emp"> UPDATE emp2 SET name=#{name},age=#{age} WHERE id=#{id} </update> <delete id="delete" parameterType="int"> DELETE FROM emp2 WHERE id=#{id} </delete> <!-- 使用ResultMap 解决表的字段名和实体类的属性名不一致的情况 --> <!-- 处理表的字段名和实体类的属性名的对应关系 --> <!-- property对应javabean的属性名,column对应数据库字段名 --> <resultMap type="entity.Emp2" id="emp2Map"> <result property="ename" column="name" /> <result property="emapNo" column="id" /> </resultMap> <select id="findById2" parameterType="int" resultMap="emp2Map"> SELECT * FROM emp2 WHERE id=#{id} </select> </mapper>
package testCase; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Before; import org.junit.Test; import com.stevezong.mybatis.entity.dao.EmpDAO; import entity.Emp; import entity.Emp2; public class TestCase { private SqlSession ss; @Before public void init() { SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder(); SqlSessionFactory ssf = ssfb.build(TestCase.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml")); ss = ssf.openSession(); } @Test public void t1() { /** * getMapper 方法返回一个符合Mapper映射器(EmpDAO)要求的对象 * */ EmpDAO dao = ss.getMapper(EmpDAO.class); Emp emp = new Emp(); emp.setName("王八"); emp.setAge(new Double(22)); dao.save(emp); ss.commit(); List<Emp> emps = dao.findAll(); System.out.println(emps); Emp emp2 = dao.findById(4); System.out.println(emp2); dao.delete(2); ss.commit(); Emp emp3 = new Emp(); emp3.setName("丽丽"); emp3.setAge(new Double(88)); emp3.setId(10); dao.modify(emp3); ss.commit(); Emp2 emp4 = dao.findById2(3); System.out.println(emp4); ss.close(); } }
spring 集成 mybatis
1、导包
spring-webmvc
mybatis
mybatis-spring
spring-jdbc
mysql
dbcp(c3p0)
2、添加spring的配置文件
mybatis 的配置信息可以添加到spring的配置文件中
3、实体类
entity
4、映射文件
XML
5、Mapper映射器
DAO接口
6、在spring 的配置文件当中,添加MapperScannerConfigurer bean 该bean 负责条用SqlSession的getMapper方法
创建符合Mapper映射器要求的对象,
该bean会将这个对象添加到spring容器里面(默认额id 是首字母小写之后的接口名,也可以在Mapper使用@Rerspository来设定id)
1、
<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.stevezong</groupId> <artifactId>mybataiszx</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.8</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.44</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>3.2.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>3.2.8.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>commons-DBCP</groupId> <artifactId>commons-DBCP</artifactId> <version>1.4</version> </dependency> </dependencies> </project>
2
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd "> <!-- mysql 信息 --> <util:properties id="dbInfo"> <prop key="user">zongxuan</prop> <prop key="password">zongxuan</prop> <prop key="url">jdbc:mysql://172.29.12.158:3306/test?useUnicode=true&characterEncoding=utf8 </prop> <prop key="driver">com.mysql.jdbc.Driver</prop> <prop key="initialSize">10</prop> <prop key="maxActive">500</prop> </util:properties> <!-- 配置连接池 --> <bean id="ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="#{dbInfo.driver}"></property> <property name="url" value="#{dbInfo.url}"></property> <property name="username" value="#{dbInfo.user}"></property> <property name="password" value="#{dbInfo.password}"></property> <property name="initialSize" value="#{dbInfo.initialSize}"></property> <property name="maxActive" value="#{dbInfo.maxActive}"></property> </bean> <!-- 配置SqlSessionFactoryBean mybatis-spring包中 spring 集成mybatis 不在需要mybatis 的配置文件,(使用SqlSessionFactoryBean来代替mybatis的配置文件) --> <bean id="ssfb" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 注入连接池, 不再使用mybatis 自带的连接池,而是使用spring管理的连接池 --> <property name="dataSource" ref="ds"></property> <property name="mapperLocations" value="classpath:entity/*.xml"></property> </bean> <!-- 配置MapperScannerConfigurer 负责扫描指定包下面的所有的Mapper映射器然后生成符合这些映射器要求的对象 其实,就是调用SqlSession的getMapper方法 另外,还会将这个对象添加到spring容器里面 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 指定Mapper映射器所在的包 --> <property name="basePackage" value="dao"></property> <!-- 只扫描特定的接口 自己开发注解 自动扫描包下所有接口 遇到带注解标记的将对应对象注册 不加不注解 不会注册 --> <property name="annotationClass" value="annotations.MyBatisRepository"></property> </bean> </beans>
3
package entity; public class Emp { private Integer id; private String name; private Double age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getAge() { return age; } public void setAge(Double age) { this.age = age; } @Override public String toString() { return "Emp [id=" + id + ", name=" + name + ", age=" + age + "]"; } }
4
<?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="dao.EmpDAO"> <!-- id 唯一 parameterType 参数类型 #{} 实体类的属性 --> <insert id="save" parameterType="entity.Emp"> INSERT INTO emp2(name,age) VALUES(#{name},#{age}) </insert> <!-- resultType:返回结果的类型 最终的 --> <select id="findAll" resultType="entity.Emp"> SELECT * FROM emp2 </select> <select id="findById" parameterType="int" resultType="entity.Emp"> SELECT * FROM emp2 WHERE id=#{id} </select> <update id="modify" parameterType="entity.Emp"> UPDATE emp2 SET name=#{name},age=#{age} WHERE id=#{id} </update> <delete id="delete" parameterType="int"> DELETE FROM emp2 WHERE id=#{id} </delete> <!-- 使用ResultMap 解决表的字段名和实体类的属性名不一致的情况 --> <!-- 处理表的字段名和实体类的属性名的对应关系 --> <resultMap type="entity.Emp2" id="emp2Map"> <result property="ename" column="name" /> <result property="emapNo" column="id" /> </resultMap> <select id="findById2" parameterType="int" resultMap="emp2Map"> SELECT * FROM emp2 WHERE id=#{id} </select> </mapper>
5
package dao; import java.util.List; import java.util.Map; import annotations.MyBatisRepository; import entity.Emp; import entity.Emp2; /** * Mapper映射器 就是一个接口 * @author steve * */ @MyBatisRepository public interface EmpDAO { void save(Emp emp); List<Emp> findAll(); Emp findById(int id); void delete(int id); void modify(Emp emp); Emp2 findById2(int id); } package annotations; public @interface MyBatisRepository { }
package test; import java.util.List; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import dao.EmpDAO; import entity.Emp; public class TestCase { private ApplicationContext ac; private EmpDAO dao; @Before public void init() { ac = new ClassPathXmlApplicationContext("applicationContext.xml"); dao = ac.getBean("empDAO", EmpDAO.class); } @Test public void t1() { List<Emp> emps = dao.findAll(); System.out.println(emps); } @Test public void t2() { Emp emp = dao.findById(5); System.out.println(emp); } }
6
mybatis 关联映射
将数据库中有关联关系的表 以实体对象引用的方法体现出来
如:在User 有Book
class User{
private List<Book> books;
}
class Book{
private User user;
}
关联的方式:
关联单个对象
Book 中
关联多个对象
User 中
在业务需要对数据库进行关联查询的时候
可以通过一条sql 语句完成关联查询,也可以通过两条sql语句进行关联查询
使用一条语句完成 语句复杂,配置简单 与数据库交互一次
使用两条语句完成 语句简单,配置复杂 与数据库交互两次
1、实体类
2、定义Dao接口
配置Mapper
关联多个对象
1、
package com.stevezong.cloud_note.entity; import java.io.Serializable; import java.util.List; /* * 类属性名和属性数据类型 * 与数据库中的保持一致 * */ public class User implements Serializable { private String cn_user_id; private String cn_user_name; private String cn_user_password; private String cn_user_token; private String cn_user_nick; private List<Book> books; public String getCn_user_id() { return cn_user_id; } public void setCn_user_id(String cn_user_id) { this.cn_user_id = cn_user_id; } public String getCn_user_name() { return cn_user_name; } public void setCn_user_name(String cn_user_name) { this.cn_user_name = cn_user_name; } public String getCn_user_password() { return cn_user_password; } public void setCn_user_password(String cn_user_password) { this.cn_user_password = cn_user_password; } public String getCn_user_token() { return cn_user_token; } public void setCn_user_token(String cn_user_token) { this.cn_user_token = cn_user_token; } public String getCn_user_nick() { return cn_user_nick; } public void setCn_user_nick(String cn_user_nick) { this.cn_user_nick = cn_user_nick; } public List<Book> getBooks() { return books; } public void setBooks(List<Book> books) { this.books = books; } @Override public String toString() { return "User [cn_user_id=" + cn_user_id + ", cn_user_name=" + cn_user_name + ", cn_user_password=" + cn_user_password + ", cn_user_token=" + cn_user_token + ", cn_user_nick=" + cn_user_nick + ", books=" + books + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((books == null) ? 0 : books.hashCode()); result = prime * result + ((cn_user_id == null) ? 0 : cn_user_id.hashCode()); result = prime * result + ((cn_user_name == null) ? 0 : cn_user_name.hashCode()); result = prime * result + ((cn_user_nick == null) ? 0 : cn_user_nick.hashCode()); result = prime * result + ((cn_user_password == null) ? 0 : cn_user_password.hashCode()); result = prime * result + ((cn_user_token == null) ? 0 : cn_user_token.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; User other = (User) obj; if (books == null) { if (other.books != null) return false; } else if (!books.equals(other.books)) return false; if (cn_user_id == null) { if (other.cn_user_id != null) return false; } else if (!cn_user_id.equals(other.cn_user_id)) return false; if (cn_user_name == null) { if (other.cn_user_name != null) return false; } else if (!cn_user_name.equals(other.cn_user_name)) return false; if (cn_user_nick == null) { if (other.cn_user_nick != null) return false; } else if (!cn_user_nick.equals(other.cn_user_nick)) return false; if (cn_user_password == null) { if (other.cn_user_password != null) return false; } else if (!cn_user_password.equals(other.cn_user_password)) return false; if (cn_user_token == null) { if (other.cn_user_token != null) return false; } else if (!cn_user_token.equals(other.cn_user_token)) return false; return true; } }
2
package com.stevezong.cloud_note.dao; import com.stevezong.cloud_note.entity.User; public interface RelationDao { public User fundUserAndBooks(String userId); }
package com.stevezong.cloud_note.dao; import com.stevezong.cloud_note.entity.User; public interface RelationDao { public User findUserAndBooks(String userId); }
<!----------------------------------------------------------------------------------------------------------------------------------------- --> <!-- 使用两条sql 语句加载数据 --> <select id="findUserAndBooks" parameterType="String" resultMap="userMap1"> SELECT * FROM cn_user WHERE cn_user_id=#{userId} </select> <resultMap id="userMap1" type="com.stevezong.cloud_note.entity.User"> <id property="cn_user_id" column="cn_user_id" /> <result property="cn_user_name" column="cn_user_name" /> <!-- 指定books属性 是一个list集合 返回类型 泛型类型 外键 --> <collection property="books" javaType="java.util.List" ofType="com.stevezong.cloud_note.entity.Book" select="findBooks" column="cn_user_id"> </collection> </resultMap> <select id="findBooks" parameterType="String" resultType="com.stevezong.cloud_note.entity.Book"> SELECT * FROM cn_notebook WHERE cn_user_id=#{userId} </select> <!----------------------------------------------------------------------------------------------------------------------------------------- --> <!-- 一条sql加载User --> <select id="findUserAndBooks1" parameterType="String" resultMap="userMap2"> SELECT * FROM cn_user u JOIN cn_notebook b ON(u.cn_user_id=b.cn_user_id) WHERE u.cn_user_id=#{userId} </select> <resultMap id="userMap2" type="com.stevezong.cloud_note.entity.User"> <!-- 定义cn_user 字段装在,不能省略 --> <id property="cn_user_id" column="cn_user_id" /> <result property="cn_user_name" column="cn_user_name" /> <result property="cn_user_password" column="cn_user_password" /> <result property="cn_user_token" column="cn_user_token" /> <result property="cn_user_nick" column="cn_user_nick" /> <collection property="books" javaType="java.util.List" ofType="com.stevezong.cloud_note.entity.Book"> <id property="cn_notebook_id" column="cn_notebook_id" /> <result property="cn_user_id" column="cn_user_id" /> <result property="cn_notebook_type_id" column="cn_notebook_type_id" /> <result property="cn_notebook_name" column="cn_notebook_name" /> <result property="cn_notebook_desc" column="cn_notebook_desc" /> <result property="cn_notebook_createtime" column="cn_notebook_createtime" /> </collection> </resultMap> <!----------------------------------------------------------------------------------------------------------------------------------------- -->
@Test public void t1() { User user = dao.findUserAndBooks("48595f52-b22c-4485-9244-f4004255b972"); //User user = dao.findUserAndBooks1("48595f52-b22c-4485-9244-f4004255b972"); System.out.println(user); System.out.println(user.getCn_user_name()); System.out.println(user.getBooks().size()); for(Book sub:user.getBooks()) { System.out.println(sub); } }
关联单个对象
通过查询笔记信心,关联用户信息
package com.stevezong.cloud_note.entity; import java.io.Serializable; import java.sql.Timestamp; public class Book implements Serializable { private String cn_notebook_id; private String cn_user_id; private String cn_notebook_type_id; private String cn_notebook_name; private String cn_notebook_desc; private Timestamp cn_notebook_createtime; private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } public String getCn_notebook_id() { return cn_notebook_id; } public void setCn_notebook_id(String cn_notebook_id) { this.cn_notebook_id = cn_notebook_id; } public String getCn_user_id() { return cn_user_id; } public void setCn_user_id(String cn_user_id) { this.cn_user_id = cn_user_id; } public String getCn_notebook_type_id() { return cn_notebook_type_id; } public void setCn_notebook_type_id(String cn_notebook_type_id) { this.cn_notebook_type_id = cn_notebook_type_id; } public String getCn_notebook_name() { return cn_notebook_name; } public void setCn_notebook_name(String cn_notebook_name) { this.cn_notebook_name = cn_notebook_name; } public String getCn_notebook_desc() { return cn_notebook_desc; } public void setCn_notebook_desc(String cn_notebook_desc) { this.cn_notebook_desc = cn_notebook_desc; } public Timestamp getCn_notebook_createtime() { return cn_notebook_createtime; } public void setCn_notebook_createtime(Timestamp cn_notebook_createtime) { this.cn_notebook_createtime = cn_notebook_createtime; } @Override public String toString() { return "Book [cn_notebook_id=" + cn_notebook_id + ", cn_user_id=" + cn_user_id + ", cn_notebook_type_id=" + cn_notebook_type_id + ", cn_notebook_name=" + cn_notebook_name + ", cn_notebook_desc=" + cn_notebook_desc + ", cn_notebook_createtime=" + cn_notebook_createtime + ", user=" + user + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((cn_notebook_createtime == null) ? 0 : cn_notebook_createtime.hashCode()); result = prime * result + ((cn_notebook_desc == null) ? 0 : cn_notebook_desc.hashCode()); result = prime * result + ((cn_notebook_id == null) ? 0 : cn_notebook_id.hashCode()); result = prime * result + ((cn_notebook_name == null) ? 0 : cn_notebook_name.hashCode()); result = prime * result + ((cn_notebook_type_id == null) ? 0 : cn_notebook_type_id.hashCode()); result = prime * result + ((cn_user_id == null) ? 0 : cn_user_id.hashCode()); result = prime * result + ((user == null) ? 0 : user.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Book other = (Book) obj; if (cn_notebook_createtime == null) { if (other.cn_notebook_createtime != null) return false; } else if (!cn_notebook_createtime.equals(other.cn_notebook_createtime)) return false; if (cn_notebook_desc == null) { if (other.cn_notebook_desc != null) return false; } else if (!cn_notebook_desc.equals(other.cn_notebook_desc)) return false; if (cn_notebook_id == null) { if (other.cn_notebook_id != null) return false; } else if (!cn_notebook_id.equals(other.cn_notebook_id)) return false; if (cn_notebook_name == null) { if (other.cn_notebook_name != null) return false; } else if (!cn_notebook_name.equals(other.cn_notebook_name)) return false; if (cn_notebook_type_id == null) { if (other.cn_notebook_type_id != null) return false; } else if (!cn_notebook_type_id.equals(other.cn_notebook_type_id)) return false; if (cn_user_id == null) { if (other.cn_user_id != null) return false; } else if (!cn_user_id.equals(other.cn_user_id)) return false; if (user == null) { if (other.user != null) return false; } else if (!user.equals(other.user)) return false; return true; } }
package com.stevezong.cloud_note.dao; import java.util.List; import com.stevezong.cloud_note.entity.Book; import com.stevezong.cloud_note.entity.User; public interface RelationDao { public User findUserAndBooks(String userId); public User findUserAndBooks1(String userId); public List<Book> findBookAndUser(); }
<!-- 两条语句加载book和关联的User信息 --> <select id="findBookAndUser" resultMap="bookMap"> SELECT * FROM cn_notebook </select> <resultMap id="bookMap" type="com.stevezong.cloud_note.entity.Book"> <association property="user" javaType="com.stevezong.cloud_note.entity.User" select="findUser" column="cn_user_id"></association> </resultMap> <select id="findUser" resultType="com.stevezong.cloud_note.entity.User" parameterType="String"> SELECT * FROM cn_user WHERE cn_user_id=#{id} </select> <!-- 一条语句加载book和关联的User信息 --> <select id="findBookAndUser1" resultMap="bookMap1"> SELECT * FROM cn_notebook nb JOIN cn_user u ON (nb.cn_user_id=u.cn_user_id) </select> <resultMap id="bookMap1" type="com.stevezong.cloud_note.entity.Book"> <id property="cn_notebook_id" column="cn_notebook_id"/> <result property="cn_user_id" column="cn_user_id"/> <result property="cn_notebook_type_id" column="cn_notebook_type_id"/> <result property="cn_notebook_name" column="cn_notebook_name"/> <result property="cn_notebook_desc" column="cn_notebook_desc"/> <result property="cn_notebook_createtime" column="cn_notebook_createtime"/> <collection property="user" javaType="com.stevezong.cloud_note.entity.User"> <id property="cn_user_id" column="cn_user_id"/> <result property="cn_user_name" column="cn_user_name"/> <result property="cn_user_password" column="cn_user_password"/> <result property="cn_user_token" column="cn_user_token"/> <result property="cn_user_nick" column="cn_user_nick"/> </collection> </resultMap>
@Test public void t2() { List<Book> books = dao.findBookAndUser(); for(Book sub:books) { System.out.println(sub.getUser()); } }
在开发中碰到用户注册的功能需要用到用户ID,但是用户ID是数据库自增生成的,这种情况上网查询后使用下面的方式配置mybatis的insert语句可以解决:
在库即可使用子层或者序列作为主键值是如何在insert执行后 立刻获取ID值
<insert id="insert" keyProperty="id" useGeneratedKeys="true" parameterType="com.demo.domain.User"> insert into User_t(name,age,addr) values(#{name},#{age},#{addr}) </insert>
@Override public int insert(User user) { int insertNum = Integer.parseInt(userMapper.insert(user) + ""); Long id = user.getId();//该对象的自增ID return insertNum; }
动态SQL
if
choose
trim
foreach
when
<update id="updateNoteByMap" parameterType="map"> UPDATE cn_note SET <trim suffixOverrides=","> <if test="title != null"> cn_note_title=#{title}, </if> <if test="body != null"> cn_note_body=#{body}, </if> <choose> <when test="time != null"> cn_note_last_modify_time=#{time} </when> <otherwise> cn_note_last_modify_time=UNIX_TIMESTAMP() </otherwise> </choose> </trim> WHERE cn_note_id=#{noteId} </update>
<delete id="deleteNotes" parameterType="map"> DELETE FROM cn_note WHERE <if test="status != null"> cn_note_status_id=#{status} AND </if> cn_note_id IN <foreach collection="ids" item="id" open="(" separator="," close=")"> #{id} </foreach> </delete>
#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
#{} 占位符
SELECT
*
FROM
emp
WHERE
name=#{name}
SELECT * FROM emp WHERE name ='张三'
${} 字符串拼接
SELECT
*
FROM
emp
WHERE
name LIKE '%${name}%'
SELECT * FROM emp WHERE name LIKE '%张三%'
在使用#{} 的时候 里面可以随便写 #{v},#{value},#{hhhg},#{asdf},#{bbb},#{aaaa},#{name}
在使用${} 的事件 里面只能用 value => ${value}
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编程中对结果的解析处理过程。
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可以查询一条或多条记录。
mysql自增主键返回
查询id的sql
SELECT LAST_INSERT_ID()
通过修改User.xml映射文件,可以将mysql自增主键返回:
如下添加selectKey 标签
<!-- 保存用户 --> <insert id="saveUser" parameterType="cn.itcast.mybatis.pojo.User"> <!-- selectKey 标签实现主键返回 --> <!-- keyColumn:主键对应的表中的哪一列 --> <!-- keyProperty:主键对应的pojo中的哪一个属性 --> <!-- order:设置在执行insert语句前执行查询id的sql,孩纸在执行insert语句之后执行查询id的sql --> <!-- resultType:设置返回的id的类型 --> <selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="int"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO `user` (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address}) </insert>
LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。
在java代码中 直接 user.getId();就可以获取到Id的值了
Mysql使用 uuid实现主键
需要增加通过select uuid()得到uuid值
<!-- 保存用户 --> <insert id="saveUser" parameterType="cn.itcast.mybatis.pojo.User"> <!-- selectKey 标签实现主键返回 --> <!-- keyColumn:主键对应的表中的哪一列 --> <!-- keyProperty:主键对应的pojo中的哪一个属性 --> <!-- order:设置在执行insert语句前执行查询id的sql,在执行insert语句之后执行查询id的sql --> <!-- resultType:设置返回的id的类型 --> <selectKey keyColumn="id" keyProperty="id" order="BEFORE" resultType="string"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO `user` (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address}) </insert>
注意这里使用的order是“BEFORE”
在java代码中 直接 user.getId();就可以获取到Id的值了
mybatis与hibernate不同
Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。
Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。
Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。
总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。
SqlMapConfig.xml中配置的内容和顺序如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
<!-- 根据条件查询用户 --> <select id="queryUserByWhere" parameterType="user" resultType="user"> SELECT id, username, birthday, sex, address FROM `user` WHERE 1=1 <if test="sex != null and sex != ''"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </select>
升级
<!-- 根据条件查询用户 --> <select id="queryUserByWhere" parameterType="user" resultType="user"> SELECT id, username, birthday, sex, address FROM `user` <!-- where标签可以自动添加where,同时处理sql语句中第一个and关键字 --> <where> <if test="sex != null"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </where> </select>
Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。
再次升级
片段,如下:
<!-- 根据条件查询用户 --> <select id="queryUserByWhere" parameterType="user" resultType="user"> <!-- SELECT id, username, birthday, sex, address FROM `user` --> <!-- 使用include标签加载sql片段;refid是sql片段id --> SELECT <include refid="userFields" /> FROM `user` <!-- where标签可以自动添加where关键字,同时处理sql语句中第一个and关键字 --> <where> <if test="sex != null"> AND sex = #{sex} </if> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> </where> </select> <!-- 声明sql片段 --> <sql id="userFields"> id, username, birthday, sex, address </sql>
<!-- 根据ids查询用户 --> <select id="queryUserByIds" parameterType="queryVo" resultType="user"> SELECT * FROM `user` <where> <!-- foreach标签,进行遍历 --> <!-- collection:遍历的集合,这里是QueryVo的ids属性 --> <!-- item:遍历的项目,可以随便写,,但是和后面的#{}里面要一致 --> <!-- open:在前面添加的sql片段 --> <!-- close:在结尾处添加的sql片段 --> <!-- separator:指定遍历的元素之间使用的分隔符 --> <foreach collection="ids" item="item" open="id IN (" close=")" separator=","> #{item} </foreach> </where> </select>
在 多个id 使用 int[] ids = new int[] {1,2,3};
collection 的值就必须要用array 规定
<select id="queryUserByIds" parameterType="queryVo" resultType="user"> SELECT * FROM `user` <where> <!-- foreach标签,进行遍历 --> <!-- collection:遍历的集合,这里是QueryVo的ids属性 --> <!-- item:遍历的项目,可以随便写,,但是和后面的#{}里面要一致 --> <!-- open:在前面添加的sql片段 --> <!-- close:在结尾处添加的sql片段 --> <!-- separator:指定遍历的元素之间使用的分隔符 --> <foreach collection="array" item="item" open="id IN (" close=")" separator=","> #{item} </foreach> </where> </select>
在使用 list的时候 值就是用 list
mybatis 自带的查询条件
TbItemExample example = new TbItemExample();//逆向工程生成的
Criteria criteria = example.createCriteria();