Mybatis快速入門
(部分代碼使用項目不同)
概述
Mybatis是一個持久層框架,用java編寫
它封裝了jdbc操作的許多細節,使開發者只需要關注sql語句本身,無需關注註冊驅動,創建連接等繁雜過程
它使用了ORM思想實現了結果集的封裝
ORM:
Object Relational Mapping 對象關係映射
對象指面向對象
關係指關係型數據庫
Java到MySql的映射,開發者可以以面向對象的思想來管理數據庫
Mybatis是一個實現了數據庫持久化的開源框架,簡單理解就是對JDBC進行封裝
簡單的說:
就是把數據庫表和實體類及實體類的屬性對應起來,讓我們可以操作實體類就實現操作數據庫表
表 類
user user
id userId
user_name userName
實體類中的屬性和數據庫的字段名稱保持一致
優點:
1.與JDBC相比,減少了50%以上的代碼量。
2.MyBatis是最簡單的持久化框架,小巧並且簡單易學。
3.MyBatis相當靈活,不會對應用程序或者數據庫的現在設計強加任何影響,SQL寫在XML裏,從程序代碼中徹底分離,降低耦合度,便於統一管理和優化,並可重用。
4.提供XML標籤,支持編寫動態SQL語句。
5.提供映射標籤,支持對象與數據庫的ORM字段關係映射。
缺點:
1.SQL語句的編寫工作量較大,尤其是字段多,關聯表多時,更是如此,對開發人員編寫SQL語句的功底有一定要求。
2.SQL語句依賴於數據庫,導致數據庫移植性差,不能隨意更換數據庫。
-
SqlSessionFactoryBuilder
build()
-
SqlSessionFactory
openSession()
-
SqlSession
入門
- 新建Maven工程,pom.xml
<dependencies>
<dependency>
<group>org.mybatis</group>
<artifactId>mybatis</artifactld>
<version>3.4.5</version>
</dependency>
</dependencies>
-
新建數據表
use mybatis; create table t_account( id int primary key auto_increment, usename varchar(11), password varchar(11), age int )
-
新建數據庫實體類
package com.zhh.entity; import lombok.Data; @Data public class Account { private long id; private String username; private String password; private int age; }
-
創建MyBatis的配置文件Config.xml文件名可自定義,在resources中創建
<?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運行環境--> <enviroments default="development"> <enviroment id="development"> <!--配置JDBC事務管理--> <transactionManager type="JDBC"></transactionManager> <!--POOLED配置JDBC數據源連接池--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/webshop?useUnicode=true&characterEncoding=utf8"></property> <property name="username" value="root"></property> <property name="password" value="123456"></property> </dataSource> </enviroment> </enviroments> </configuration>
MyBatis開發方式
使用原生接口
Mybatis框架需要開發者自定義SQL語句,寫在Mapper.xml文件中,實際開發中,會爲每個實體類創建對應的Mapper.xml,定義管理該對象數據的SQL.
AccountMapper.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="com.iweb.dao.IUserDao">
<!-- id:statement的id 或者叫做sql的id-->
<!-- parameterType:聲明輸入參數的類型 -->
<!-- resultType:聲明輸出結果的類型,應該填寫pojo的全路徑 -->
<!-- #{}:輸入參數的佔位符,相當於jdbc的? -->
<!-- 通過id查詢一個用戶 -->
<select id="findAll" resultType="com.iweb.domain.User">
select * from user;
</select>
<!--四種常用標籤-->
<insert id="save" parameterType="com.zhh.entity.Account">
insert into t_account(username,password,age)values(#{username},#{password},#{age})
</insert>
<update id=""></update>
<delete id=""></delete>
<select id=""></select>
</mapper>
- namespace通常設置爲文件所在包+文件名的形式
- id是實際調用Mybatis方法時需要用到的參數
- parameterType是調用對應方法時參數的數據類型
在全局配置文件config.xml中註冊AccountMapper.xml註冊xml
resource後寫上文件路徑,注意此時用斜槓不要用點,因爲會引起衝突
<!--註冊AccountMapper.xml-->
<mappers>
<mapper resource="com/zhh/mapper/Account.xml"></mapper>
</mappers>
調用MyBatis原生接口來執行操作
public class MybatisTest {
/**
* 入門案例
* @param args
*/
public static void main(String[] args) throws IOException {
// 1.讀取配置文件
InputStream in= Resources.getResourceAsStream("Config.xml");
// 2.創建SqlSessionFactory
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
SqlSessionFactory factory=builder.build(in);
// 3.使用工廠生產SqlSession對象
SqlSession session=factory.openSession();
String statement="com.zhh.mapper.AccoutMapper.save";
Account account=new Account(1L,"張三",12);
session.insert(statement,account);
// 4.釋放資源
session.commit();
}
}
使用Mapper代理實現自定義接口(推薦)
- 自定義接口,定義相關業務方法
- 編寫與方法相對應的Mapper.xml
1.自定義接口
package com.zhh.repository;
import com.zhh.entity.Acount;
import java.util.List;
public interface AccountRepository{
public int save(Account account);
public int update(Account account);
public int deleteById(long id);
public List<Account> findAll();
public Account findById(long id);
}
2.創建接口對應的Mapper.xml,定義接口方法對應的SQL語句。statement標籤會根據SQL執行的業務選擇。MyBatis框架會根據規則自動創建接口實現類的代理對象。(後面的代碼用了自己的例子)
規則:
- Mapper.xml中namespace爲接口的全類名。
- Mapper.xml中statement的id爲接口中對應的方法名
- Mapper.xml中statement的parameterType和接口對應方法的參數類型一致
- Mapper.xml中statement的resultType和接口中對應方法的返回值類型一致
<?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="com.iweb.dao.IUserDao">
<!-- id:statement的id 或者叫做sql的id-->
<!-- parameterType:聲明輸入參數的類型 -->
<!-- resultType:聲明輸出結果的類型,應該填寫pojo的全路徑 -->
<!-- #{}:輸入參數的佔位符,相當於jdbc的? -->
<!-- 通過id查詢一個用戶 -->
<select id="findAll" resultType="com.iweb.domain.User">
select * from user;
</select>
<select id="findById" parameterType="long" resultType="com.iweb.domain.User">
select * from user where id=#{id};
</select>
<insert id="save" parameterType="com.iweb.domain.User" >
insert into user(id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address});
</insert>
<update id="update" parameterType="com.iweb.domain.User">
update user set id=#{id},username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#
{id};
</update>
<delete id="deleteById" parameterType="long">
delete from user where id=#{id};
</delete>
</mapper>
3.在config.xml中註冊
<mappers>
<!-- <mapper class="com.xl.dao.AccountDao"/>-->
<mapper resource="com/iweb/dao/IUserDao.xml"></mapper>
<package name="com.xl.dao"/>
</mappers>
4.調用接口的代理對象完成相關的業務操作
public class MybatisTest {
/**
* 入門案例
* @param args
*/
public static void main(String[] args) throws IOException {
// 1.讀取配置文件
InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.創建SqlSessionFactory
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
SqlSessionFactory factory=builder.build(in);
// 3.使用工廠生產SqlSession對象
SqlSession session=factory.openSession();
// 4.使用SqlSession創建Dao接口的代理對象
IUserDao userDao=session.getMapper(IUserDao.class);
// 5.使用代理對象執行方法
//添加
User user1=new User(6,"張華", Date.valueOf("1997-11-27"),"男","安徽");
userDao.save(user1);
session.commit();
//查找全部
List<User> users=userDao.findAll();
for(User user:users){
System.out.println(user);
}
//按Id查找
User user2=userDao.findById(1L);
System.out.println(user2);
//更新數據
user2.setId(1L);
user2.setUsername("大華");
user2.setBirthday(Date.valueOf("1997-11-27"));
user2.setSex("男");
user2.setAddress("安徽");
int result=userDao.update(user2);
//刪除數據
int result=userDao.deleteById(4L);
System.out.println("result");
session.commit();
// 6.釋放資源
session.close();
session.close();
}
}
Mapper.xml
-
statement標籤:select、update、delete、insert分別對應查改刪增
-
parameterType:參數數據類型
1.基本數據類型,通過id查詢Account
<select id="findById" parameterType="long" resultType="com.zhh.entity.Account"> select * from t_account where id=#{id}; </select>
2.String類型,通過name查詢Account
<select id="findName" parameterType="java.lang.String" resultType="com.zhh.entity.Account"> select * from t_account where username=#{username}; </select>
3.包裝類,通過id查詢Account
<select id="findById" parameterType="java.lang.Long" resultType="com.zhh.entity.Account"> select * from t_account where id=#{id}; </select>
4.多個參數,通過username和age查詢Account
param也可以用arg代替
<select id="findByNameAndAge" resultType="com.zhh.entity.Account"> select * from t_account where username=#{param1} and age=#{param2}; </select>
5.Java Bean
<update id="update" parameterType="com.iweb.domain.User"> update user set id=#{id},username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}; </update>
-
resultType:結果類型
1.基本數據類型,統計Account總數
<select id="count" resultType="int"> select count(id) from t_account; </select>
2.包裝類,統計Account總數
<select id="findById" resultType="com.zhh.entity.Integer"> select count(id) from t_account; </select>
3.String類型,通過id查詢Account的name
<select id="findNameById" resultType="java.lang.String"> select username from t_account where id=#{id}; </select>
4.JavaBean類型
<select id="findById" parameterType="long" resultType="com.iweb.domain.User"> select * from user where id=#{id}; </select>
-
級聯查詢
1.一對多
Student
@Data public class Student{ private long id; private String name; private Classes classes; }
Classes
@Data public class Classes{ private long id; private String name; private List<Student> students; }
StudentRepository
public interface StudentRepository{ public Student findById(long id); }
StudentRepository.xml
<resultMap id="studentMap" type="com.zhh.entity.Student"> <id colmumn="id" property="id"></id> <result column="name" property="name"></result> <association property="classes" javaType="com.zhh.entity.Classes"> <id column="cid" property="id"></id> <result column="cname" property="name"></result> </association> </resultMap> <select id="findById" parameterType="long" resultMap="studentMap"> select s.id,s.name,c.id as cid,c.name as cname from student s ,classes c where s.id=#{id} and s.cid=c.id; </select>
ClassesRepository.xml
<resultMap id="classesMap" type="com.zhh.entity.Classes"> <id colmumn="cid" property="id"></id> <result column="cname" property="name"></result> <collection property="students" ofType="com.zhh.entity.Student"> <id column="id" property="id"></id> <result column="name" property="name"></result> </collection> </resultMap>
!!!實體類中如果一個學生對應一個班級,一個對象就用
是個集合就用
2.多對多
Customer
@Data public class Customer{ private long id; private String name; private List<Goods> goods; }
Goods
@Data public class Goods{ private long id; private String name; private List<Customer> customer; }
CustomerRepository
public interface CustomerRepository{ public Customer findById(long id); }
GoodsRepository
public interface GoodsRepository{ public Goods findById(long id); }
CustomerRepository.xml
<resultMap id="customerMap" type="com.zhh.entity.Customer"> <id colmumn="cid" property="id"></id> <result column="cname" property="name"></result> <collection property="goods" ofType="com.zhh.entity.Goods"> <id column="gid" property="id"></id> <result column="gname" property="name"></result> </collection> </resultMap> <select id="findById" parameterType="long" resultMap="customerMap"> select c.id cid,c.name cname,g.id gid,g.name gname from customer c ,goods g,customer_goods cg where c.id=#{id} and cg.cid=c.id and cg.gid=g.id; </select>
GoodsRepository.xml
<resultMap id="goodsMap" type="com.zhh.entity.Goods"> <id colmumn="gid" property="id"></id> <result column="gname" property="name"></result> <collection property="customers" ofType="com.zhh.entity.customer"> <id column="cid" property="id"></id> <result column="cname" property="name"></result> </collection> </resultMap> <select id="findById" parameterType="long" resultMap="goodsMap"> select c.id cid,c.name cname,g.id gid,g.name gname from customer c ,goods g,customer_goods cg where g.id=#{id} and cg.cid=c.id and cg.gid=g.id; </select>
逆向工程
MyBatis框架需要:實體類、自定義Mapper接口、Mapper.xml
傳統的開發中上述的三個組件需要開發者手動創建,逆向工程可以幫助開發者自動創建三個組件,減輕開發者的工作量,提高工作效率。
如何使用
MyBatis Generator,簡稱MBG,是一個專門爲MyBatis框架開發者定製的代碼生成器,可自動生成MyBatis框架所有的實體類、Mapper接口、Mapper.xml,支持基本的CRUD操作,但是一些複雜的SQL需要開發者自己來完成。
-
新建Maven工程,pom.xml
<dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.2</version> </dependency> </dependencies>
-
創建MBG配置文件generatorConfig.xml(可自定義名字)
1.jdbcConnection配置數據庫連接信息
2.javaModelGenerator配置JavaBean的生成策略
3.sqlMapGenerator配置SQL映射文件策略
4.javaClientGenerator配置Mapper接口的生成策略
5.table配置目標數據表(tableName:表名,domainObjectName:javaBean類名)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <context id="testTables" targetRuntime="MyBatis3"> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8" userId="root" password="123456" > </jdbcConnection> <javaModelGenerator targetPackage="com.zhh.entity" targetProject="./src/main/java"></javaModelGenerator> <sqlMapGenerator targetPackage="com.zhh.repository" targetProject="./src/main/java"></sqlMapGenerator> <javaClientGenerator type="XMLMAPPER" targetPackage="com.zhh.repository" targetProject="./src/main/java"></javaClientGenerator> <table tableName="t_user" domainObjectName="User"></table> </context> </generatorConfiguration>
-
創建Generator執行類
public class Main { public static void main(String[] args) throws IOException, XMLParserException { List<String> warings=new ArrayList<String>(); boolean overwrite=true; //配置文件 String genCig="/generatorConfig.xml"; File configFile=new File(Main.class.getResource(genCig).getFile()); ConfigurationParser configurationParser=new ConfigurationParser(warings); Configuration configuration=null; try { configuration=configurationParser.parseConfiguration(configFile); } catch (IOException e) { e.printStackTrace(); } catch (XMLParserException e) { e.printStackTrace(); } DefaultShellCallback callback=new DefaultShellCallback(overwrite); MyBatisGenerator myBatisGenerator=null; try { myBatisGenerator =new MyBatisGenerator(configuration,callback,warings); } catch (InvalidConfigurationException e) { e.printStackTrace(); } try { myBatisGenerator.generate(null); } catch (SQLException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }
MyBatis延遲加載
-
什麼是延遲加載?
延遲加載也叫懶加載、惰性加載,使用延遲加載可以提高程序的運行效率,針對數據持久層的操作,在某些特定情況下去訪問特定的數據庫,在其他情況下不訪問某些表,從一定程度上減少了Java應用與數據庫的交互次數。
查詢學生和班級的時,學生和班級是兩張不同的表,如果當前需求只需要獲取學生的信息,那麼查詢學生單表即可,如果需要通過學生獲取對應的班級信息,則必須查詢兩張表。
不同的業務需求,需要查詢不同的表,根據具體的業務需求來動態減少數據表查詢
public interface StudentRepository{ public Student findByIdLazy(long id); }
<resultMap id="studentMapLazy" type="com.zhh.entity.Student"> <id colmumn="id" property="id"></id> <result column="name" property="name"></result> <association property="classes" javaType="com.zhh.entity.Classes" select="com.zhh.respository.ClassesRepository.findByIdLazy" column="cid"> </association> </resultMap> <select id="findByIdLazy" parameterType="long" resultMap="studentMapLazy"> select * from student where id=#{id}; </select>
public interface ClassesRepository{ public Classes findByIdLazy(long id); }
<select id="findByIdLazy" parameterType="long" resultType="com.zhh.entity.Classes"> select * from classes where id=#{id}; </select>
nt">
select * from student where id=#{id};
```java
public interface ClassesRepository{
public Classes findByIdLazy(long id);
}
<select id="findByIdLazy" parameterType="long" resultType="com.zhh.entity.Classes">
select * from classes where id=#{id};
</select>