future方法用于在系统资源可用时在单独的线程中运行进程,我们可以将future方法用于任何我们希望在其自己的线程中异步运行的操作。
·external Web services callout
·Trigger中DML实行后,再次CallOut操作。
·在方法前指定@future标签
·必须时static方法并且返回值时void
·引数必须是基本数据类型或基本数据类型的集合
·引数不能使用标准的Object类型或者sObject类型
·引数一般使用List record IDs来传递数据
global class SomeClass {
@future
public static void someFutureMethod(List<Id> recordIds) {
List<Account> accounts = [Select Id, Name from Account Where Id IN :recordIds];
// process account records to do awesome stuff
}
}
·引数不能使用标准的Object类型或者sObject类型的理由,future方法执行中需要等待的时间,这个过程中Object中的值有变化的可能,容易造成不好的影响。
·future方法不能保证执行顺序,2个future方法很容易同时执行,如果同时更新一条数据,容易造成锁表,发生error。
·future方法不能调用另一个同为future的方法
现做成两个方法,一个不指定@future,另一个指定@future,并验证结果正确与否。
public with sharing class ExampleFuture {
public static void methodNoFuture(Set<Id> idsSet) {
String sql = 'SELECT Id,Name FROM Opportunity where Id in :idsSet';
List<Opportunity> opps = Database.query(sql);
List<Opportunity> newOppList = new List<Opportunity>();
for(Opportunity opp : opps) {
opp.stageName = 'Closed Won';
newOppList.add(opp);
}
update newOppList;
System.debug('>>>>>>>>methodNoFuture::'+System.isQueueable());
}
@future
public static void methodFuture(Set<Id> idsSet) {
String sql = 'SELECT Id,Name FROM Opportunity where Id in :idsSet';
List<Opportunity> opps = Database.query(sql);
List<Opportunity> newOppList = new List<Opportunity>();
for(Opportunity opp : opps) {
opp.stageName = 'Closed Won';
newOppList.add(opp);
}
update newOppList;
System.debug('>>>>>>>>methodFuture::'+System.isQueueable());
}
}
下边是测试类,区别是调用future方法时,调用的地方必须在【Test.startTest();】和【Test.stopTest();】之间,否则调用不成功。
@isTest
public with sharing class ExampleFutureTest {
static testMethod void FutureTest001() {
List<Opportunity> oppList = new List<Opportunity>();
for(integer i = 0; i<200; i++){
Opportunity oppItem = new Opportunity(Name='methodNoFutureOpportunity'+ i,
StageName='Perception Analysis',
CloseDate = Date.Today(),
DeleteFlg__c = true);
oppList.add(oppItem);
}
insert oppList;
Map<Id, Opportunity> oppsMap = new Map<Id, Opportunity>(oppList);
ExampleFuture.methodNoFuture(oppsMap.keySet());
List<Opportunity> oppUpdateList = [SELECT Id,StageName FROM Opportunity WHERE DeleteFlg__c = true];
System.assertEquals(200, oppUpdateList.size());
if (oppUpdateList != null && oppUpdateList.size() >0) {
for (Opportunity oppUpdate : oppUpdateList) {
System.assertEquals('Closed Won', oppUpdate.StageName);
}
}
}
static testMethod void FutureTest002() {
List<Opportunity> oppList = new List<Opportunity>();
for(integer i = 0; i<200; i++){
Opportunity oppItem = new Opportunity(Name='methodFutureOpportunity'+ i,
StageName='Perception Analysis',
CloseDate = Date.Today(),
DeleteFlg__c = true);
oppList.add(oppItem);
}
insert oppList;
Map<Id, Opportunity> oppsMap = new Map<Id, Opportunity>(oppList);
Test.startTest();
ExampleFuture.methodFuture(oppsMap.keySet());
Test.stopTest();
List<Opportunity> oppUpdateList = [SELECT Id,StageName FROM Opportunity WHERE DeleteFlg__c = true];
System.assertEquals(200, oppUpdateList.size());
if (oppUpdateList != null && oppUpdateList.size() >0) {
for (Opportunity oppUpdate : oppUpdateList) {
System.assertEquals('Closed Won', oppUpdate.StageName);
}
}
}
}
执行结果:
某些 sObject 上的 DML 操作不能与同一事务中其他 sObject 上的 DML 混合执行,例如以下当插入Account表数据时,需要同时插入带有Role的User,这时插入user方法需指定@future
public with sharing class ExampleMixedDMLFuture {
public static void useFutureMethod() {
// First DML operation
Account a = new Account(Name='Acme');
insert a;
System.debug('>>>>>>>>useFutureMethod11::'+System.isQueueable());
// This next operation (insert a user with a role)
// can't be mixed with the previous insert unless
// it is within a future method.
// Call future method to insert a user with a role.
ExampleInsertUserFuture.insertUserWithRole(
'xiang@awcomputing.com', 'xiang',
'yu@awcomputing.com', 'yu');
System.debug('>>>>>>>>useFutureMethod22::'+System.isQueueable());
}
}
public with sharing class ExampleInsertUserFuture {
@future
public static void insertUserWithRole(String uname, String al, String em, String lname) {
System.debug('>>>>>>>>insertUserWithRole111::'+System.isQueueable());
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
UserRole r = [SELECT Id FROM UserRole WHERE Name='COO'];
// Create new user with a non-null user role ID
User u = new User(alias = al, email=em,
emailencodingkey='UTF-8', lastname=lname,
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
timezonesidkey='America/Los_Angeles',
username=uname);
insert u;
System.debug('>>>>>>>>insertUserWithRole222::'+System.isQueueable());
}
}
测试类:
@isTest
public with sharing class ExampleMixedDMLFutureTest {
@isTest static void test1() {
User thisUser = [SELECT Id FROM User WHERE Id = :UserInfo.getUserId()];
// System.runAs() allows mixed DML operations in test context
System.runAs(thisUser) {
// startTest/stopTest block to run future method synchronously
Test.startTest();
ExampleMixedDMLFuture.useFutureMethod();
Test.stopTest();
}
// The future method will run after Test.stopTest();
// Verify account is inserted
Account[] accts = [SELECT Id from Account WHERE Name='Acme'];
System.assertEquals(1, accts.size());
// Verify user is inserted
User[] users = [SELECT Id from User where username='xiang@awcomputing.com'];
System.assertEquals(1, users.size());
}
}
执行结果:
在同一事务中执行 DML 操作时,不能将以下 sObject 与其他 sObject 一起使用
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。